name: toc
Table of Contents
class: inverse, center, middle
Pre-bootcamp HW
Talk about your analysis on the
weather data
in groups of 2-3
Let’s get it all out there
When you think of R what comes to mind?
name: whyr
Why are you here wanting to learn R?
Why should you learn R?
- R is free, R improves, R has existed for 40+ years
- Students can show what they have learned to a potential employer easily
- The support system for R is actually much better than some people say
But as a professor, why should you learn R?
- R and R Markdown will save you TONS of time. Long term thinking is key.
- You can easily tweak your code if you need to do another analysis
- Remembering what drop-down menu some thing is in two years from now in a different program will be hard
- Remembering to copy-and-paste your updated plots/analysis into your word processor is a pain and error prone
But as a professor, why should you learn R?
class: inverse, center, middle
DEMO in RStudio
with R Markdown
class: center, middle
What this bootcamp is
- Designed for all levels of knowledge and background
What this bootcamp is not
- A thorough development of machine learning
techniques applied to big data
–
- A discussion on the role of p-values in science
–
- A tutorial on how to work with base R subsetting and base R graphics
What I hope you’ll learn
- That R is not as scary as it used to be.
–
- Learning how to Google is an incredibly valuable skill.
–
- That having students turn in assignments using R scripts and R Markdown provides an efficient way to check their work and their analyses easily.
What I hope you’ll learn
- That the R packages you will use in this workshop are the same ones that are used by scientists and graduate programs all over the world
–
- That teaching students how to use open-source tools is what is best for them long term
–
- That students with no programming background can do great things in only a few weeks
Pieces of advice
- Scaffold & support as a foreign languages do
–
- To be able to use R (and really any other language), students need more than a few assignments and more than a weekly lab
–
- Make use of RStudio Projects (students have a really hard time navigating directory structures)
Pieces of advice
My opinion
- Have students work on writing their code in R script files and documenting their errors
- This is the same workflow that DataCamp uses
–
- Show students R Markdown after a few weeks of working with the script file
- I’ve found it is hard for students to learn R and R Markdown from the start
- Better to have them use R Markdown in groups initially
class: inverse, center, middle
R Data Types
The bare minimum needed for understanding today
Vector/variable - Type of vector (int, num, chr, lgl, date)
–
Data frame - Vectors of (potentially) different types - Each vector has the same number of rows
The bare minimum needed for understanding today
library(tibble)
library(lubridate)
ex1 <- data_frame(
vec1 = c(1980, 1990, 2000, 2010),
vec2 = c(1L, 2L, 3L, 4L),
vec3 = c("low", "low", "high", "high"),
vec4 = c(TRUE, FALSE, FALSE, FALSE),
vec5 = ymd(c("2017-05-23", "1776/07/04", "1983-05/31", "1908/04-01"))
)
ex1
–
class: center, middle
The tidyverse is a collection of R packages that share common philosophies and are designed to work together.

Beginning steps
Frequently the first thing to do when given a dataset is to - identify the observational unit, - specify the variables, - give the types of variables you are presented with, and - check that the data is tidy. (TO COME)
This will help with - choosing the appropriate plot, - summarizing the data, and - understanding which inferences/models can be applied.
class: inverse, center, middle name: viz
Data Visualization

Inspired by Hans Rosling

- What are the variables here?
- What is the observational unit?
- How are the variables mapped to aesthetics?
Grammar of Graphics
.left-column[ Wilkinson (2005) laid out the proposed “Grammar of Graphics”]
.right-column[
]
Grammar of Graphics in R
.left-column[ Wickham implemented the grammar in R in the ggplot2 package]
.right-column[
]
Grammar of Graphics elsewhere
class: center, middle
# What is a statistical graphic?
## A mapping of
data variables
to
aes()thetic attributes
## of geom_etric objects. |
class: inverse, center, middle
Reproducing the plots in ggplot2
1. A scatterplot
library(ggplot2)
ggplot(data = simple_ex, mapping = aes(x = A, y = B)) +
geom_point()
–

Reproducing the plots in ggplot2
2. A scatter plot where the color of the points corresponds to group
library(ggplot2)
ggplot(data = simple_ex, mapping = aes(x = A, y = B)) +
geom_point(mapping = aes(color = D))
–

Reproducing the plots in ggplot2
3. A scatter plot where the size of the points corresponds to C
library(ggplot2)
ggplot(data = simple_ex, mapping = aes(x = A, y = B, size = C)) +
geom_point()
–

Reproducing the plots in ggplot2
4. A line graph
library(ggplot2)
ggplot(data = simple_ex, mapping = aes(x = A, y = B)) +
geom_line()
–

Reproducing the plots in ggplot2
5. A line graph where the color of the line corresponds to D with points added that are all blue of size 4.
library(ggplot2)
ggplot(data = simple_ex, mapping = aes(x = A, y = B)) +
geom_line(mapping = aes(color = D)) +
geom_point(color = "forestgreen", size = 4)
–

The Five-Named Graphs
The 5NG of data viz
- Scatterplot:
geom_point()
Line graph: geom_line()
- Histogram:
geom_histogram()
- Boxplot:
geom_boxplot()
- Bar graph:
geom_bar()
class: center, middle
More ggplot2 examples
Histogram
library(nycflights13)
ggplot(data = weather, mapping = aes(x = humid)) +
geom_histogram(bins = 20, color = "black", fill = "darkorange")

Boxplot (broken)
library(nycflights13)
ggplot(data = weather, mapping = aes(x = month, y = humid)) +
geom_boxplot()

Boxplot (almost fixed)
library(nycflights13)
ggplot(data = weather, mapping = aes(x = month, group = month, y = humid)) +
geom_boxplot()
Boxplot (fixed)
library(nycflights13)
ggplot(data = weather, mapping = aes(x = month, group = month, y = humid)) +
geom_boxplot() +
scale_x_continuous(breaks = 1:12)

Bar graph
library(fivethirtyeight)
ggplot(data = bechdel, mapping = aes(x = clean_test)) +
geom_bar()

How about over time?
library(dplyr)
year_bins <- c("'70-'74", "'75-'79", "'80-'84", "'85-'89",
"'90-'94", "'95-'99", "'00-'04", "'05-'09",
"'10-'13")
bechdel <- bechdel %>%
mutate(five_year = cut(year,
breaks = seq(1969, 2014, 5),
labels = year_bins)) %>%
mutate(clean_test = factor(clean_test,
levels = c("nowomen", "notalk", "men",
"dubious", "ok")))
How about over time? (Stacked)
library(fivethirtyeight)
library(ggplot2)
ggplot(data = bechdel,
mapping = aes(x = five_year, fill = clean_test)) +
geom_bar()

How about over time? (Side-by-side)
library(fivethirtyeight)
library(ggplot2)
ggplot(data = bechdel,
mapping = aes(x = five_year, fill = clean_test)) +
geom_bar(position = "dodge")

How about over time? (Stacked proportional)
library(fivethirtyeight)
library(ggplot2)
ggplot(data = bechdel,
mapping = aes(x = five_year, fill = clean_test)) +
geom_bar(position = "fill", color = "black")

class: center, middle
The tidyverse/ggplot2 is for beginners and
for data science professionals!

Practice
Produce appropriate 5NG with R package & data set in [ ], e.g., [nycflights13 \(\rightarrow\) weather]
Does age predict recline_rude?
[fivethirtyeight \(\rightarrow\) na.omit(flying)]
Distribution of age by sex
[okcupiddata \(\rightarrow\) profiles]
Does budget predict rating?
[ggplot2movies \(\rightarrow\) movies]
Distribution of log base 10 scale of budget_2013
[fivethirtyeight \(\rightarrow\) bechdel]
HINTS

class: inverse, center, middle
DEMO of ggplot2 in RStudio
class: center, middle
Determining the appropriate plot

class: inverse, center, middle name: wrangle
Day 2
Data Wrangling
gapminder data frame in the gapminder package
library(gapminder)
gapminder
Base R versus the tidyverse
Say we wanted mean life expectancy across all years for Asia
–
# Base R
asia <- gapminder[gapminder$continent == "Asia", ]
mean(asia$lifeExp)
[1] 60.0649
–
library(dplyr)
gapminder %>% filter(continent == "Asia") %>%
summarize(mean_exp = mean(lifeExp))
The pipe %>%

A way to chain together commands
- It is essentially the
dplyr equivalent to the
+ in ggplot2
## The 5NG of data viz
geom_point()
geom_line()
geom_histogram()
geom_boxplot()
geom_bar()
The Five Main Verbs (5MV) of data wrangling
filter()
summarize()
group_by()
mutate()
arrange()
filter()
library(gapminder); library(dplyr)
gap_2007 <- gapminder %>% filter(year == 2007)
head(gap_2007)
- Use
== to compare a variable to a value
Logical operators
Use | to check for any in multiple filters being true:
gapminder %>%
filter(year == 2002 | continent == "Europe")
–
Logical operators
Use & or , to check for all of multiple filters being true:
gapminder %>%
filter(year == 2002, continent == "Europe")
Logical operators
Use %in% to check for any being true
(shortcut to using | repeatedly with ==)
gapminder %>%
filter(country %in% c("Argentina", "Belgium", "Mexico"),
year %in% c(1987, 1992))
–
summarize()
- Any numerical summary that you want to apply to a column of a data frame is specified within
summarize().
max_exp_1997 <- gapminder %>%
filter(year == 1997) %>%
summarize(max_exp = max(lifeExp))
max_exp_1997
–
Combining summarize() with group_by()
When you’d like to determine a numerical summary for all levels of a different categorical variable
max_exp_1997_by_cont <- gapminder %>%
filter(year == 1997) %>%
group_by(continent) %>%
summarize(max_exp = max(lifeExp))
max_exp_1997_by_cont
–
Without the %>%
It’s hard to appreciate the %>% without seeing what the code would look like without it:
max_exp_1997_by_cont <-
summarize(
group_by(
filter(
gapminder,
year == 1997),
continent),
max_exp = max(lifeExp))
max_exp_1997_by_cont
ggplot2 revisited
For aggregated data, use geom_col
ggplot(data = max_exp_1997_by_cont,
mapping = aes(x = continent, y = max_exp)) +
geom_col()
The 5MV
filter()
summarize()
group_by()
mutate()
mutate()
- Allows you to
- create a new variable with a specific value OR
- create a new variable based on other variables OR
- change the contents of an existing variable
–
gap_plus <- gapminder %>% mutate(just_one = 1)
head(gap_plus)
mutate()
- Allows you to
- create a new variable with a specific value OR
- create a new variable based on other variables OR
- change the contents of an existing variable
–
gap_w_gdp <- gapminder %>% mutate(gdp = pop * gdpPercap)
head(gap_w_gdp)
mutate()
- Allows you to
- create a new variable with a specific value OR
- create a new variable based on other variables OR
- change the contents of an existing variable
–
gap_weird <- gapminder %>% mutate(pop = pop + 1000)
head(gap_weird)
arrange()
Reorders the rows in a data frame based on the values of one or more variables
gapminder %>%
arrange(year, country)
arrange()
Can also put into descending order
gapminder %>%
filter(year > 2000) %>%
arrange(desc(lifeExp))
Don’t mix up arrange and group_by
Don’t mix up arrange and group_by
This doesn’t really do anything useful
gapminder %>% group_by(year)
Don’t mix up arrange and group_by
But this does
gapminder %>% arrange(year)
Changing of observation unit
True or False > Each of filter, mutate, and arrange change the observational unit.
–
True or False > group_by() %>% summarize() changes the observational unit.
What is meant by “joining data frames” and
why is it useful?
–

Does cost of living in a state relate to whether police officers live in the cities they patrol? What about state political ideology?
library(fivethirtyeight); library(readr); library(dplyr)
police2 <- police_locals %>% select(city, all)
ideology <- read_csv("https://ismayc.github.io/Effective-Data-Storytelling-using-the-tidyverse/datasets/ideology.csv")
police_join <- inner_join(x = police2, y = ideology, by = "city")
police_join
–
url <- paste0("https://ismayc.github.io/",
"Effective-Data-Storytelling-using-the-tidyverse/",
"datasets/cost_of_living.csv")
cost_of_living <- read_csv(url)
police_join_cost <- inner_join(
x = police_join,
y = cost_of_living,
by = "state"
)
police_join_cost %>% select(-state) %>% arrange(city)
Does cost of living in a state relate to whether police officers live in the cities they patrol? What about state political ideology?
ggplot(data = police_join_cost,
mapping = aes(x = index, y = all)) +
geom_point(mapping = aes(color = state_ideology)) +
labs(x = "Cost of Living Index", y = "% Officers Living in City")

Practice (Lay out what the resulting table should look like on paper first.)
Use the 5MV to answer problems from R data packages, e.g., [nycflights13 \(\rightarrow\) weather]
What is the maximum arrival delay for each carrier departing JFK? [nycflights13 \(\rightarrow\) flights]
Determine the top five movies in terms of domestic return on investment for 2013 scaled data
[fivethirtyeight \(\rightarrow\) bechdel]
Include the name of the destination airport as a column in the flights data frame
[nycflights13 \(\rightarrow\) flights, airports]
class: inverse, center, middle
DEMO of dplyr in RStudio
class: inverse, center, middle
Data Importing and Tidying
tidyverse packages
IMPORT
haven for SPSS, SAS, and Stata data files
jsonlite for JSON files
readxl for XLS and XLSX files
readr for CSV and TSV files (and R specific RDS files)
TIDYING
tidyr for converting “messy” into “tidy” data frames
name: import
Basics of Importing
We will begin by downloading and importing a variety of different “messy” data sets. You can download all of them in a ZIP file at http://bit.ly/reed-messy-data. The links below go to the original sources. I’ve converted these original sources into different formats.
class: center, middle, inverse
Demonstration in RStudio
Practice
- Download the four other files and import them into R using the appropriate package
- You may need to check out the help pages for the different packages
- Give them the following names:
who_df, county_pop_df, edu_county_df, and potus12_df
name: tidy class: inverse, middle, center
Tidy Data

- Each variable forms a column.
- Each observation forms a row.
- Each type of observational unit forms a table.
The third point means we don’t mix apples and oranges.
What is Tidy Data?
- Each observation forms a row. In other words, each row corresponds to a single instance of an observational unit
- Each variable forms a column:
- Some variables may be used to identify the observational units.
- For organizational purposes, it’s generally better to put these in the left-hand columns
- Each type of observational unit forms a table with the entries in the table corresponding to values.
Differentiating between neat data and tidy data
- Colloquially, they mean the same thing
- But in our context, one is a subset of the other.
Neat data is - easy to look at, - organized nicely, and - in table form.
–
Tidy data is neat but also abides by a set of three rules.
class: center, middle


Is this tidy?
|
year
|
title
|
clean_test
|
budget_2013
|
|
1995
|
Apollo 13
|
ok
|
99370665
|
|
2005
|
Brokeback Mountain
|
notalk
|
16583160
|
|
2010
|
Diary of a Wimpy Kid
|
ok
|
16023478
|
|
1984
|
Dune
|
dubious
|
100864980
|
|
1984
|
Ghostbusters
|
notalk
|
67243320
|
|
2003
|
How to Lose a Guy in 10 Days
|
men
|
63304348
|
|
2011
|
Iris
|
ok
|
5696299
|
|
2004
|
Sideways
|
ok
|
20964279
|
|
2000
|
Songcatcher
|
ok
|
2435235
|
|
2004
|
Team America: World Police
|
men
|
24663858
|
|
2010
|
Tron Legacy
|
notalk
|
213646368
|
|
2011
|
War Horse
|
notalk
|
72498355
|
name: demscore
How about this? Is this tidy?
|
country
|
1952
|
1957
|
1962
|
1967
|
1972
|
1977
|
1982
|
1987
|
1992
|
1997
|
2002
|
2007
|
|
Albania
|
-9
|
-9
|
-9
|
-9
|
-9
|
-9
|
-9
|
-9
|
5
|
5
|
7
|
9
|
|
Argentina
|
-9
|
-1
|
-1
|
-9
|
-9
|
-9
|
-8
|
8
|
7
|
7
|
8
|
8
|
|
Armenia
|
-9
|
-7
|
-7
|
-7
|
-7
|
-7
|
-7
|
-7
|
7
|
-6
|
5
|
5
|
|
Australia
|
10
|
10
|
10
|
10
|
10
|
10
|
10
|
10
|
10
|
10
|
10
|
10
|
|
Austria
|
10
|
10
|
10
|
10
|
10
|
10
|
10
|
10
|
10
|
10
|
10
|
10
|
|
Azerbaijan
|
-9
|
-7
|
-7
|
-7
|
-7
|
-7
|
-7
|
-7
|
1
|
-6
|
-7
|
-7
|
|
Belarus
|
-9
|
-7
|
-7
|
-7
|
-7
|
-7
|
-7
|
-7
|
7
|
-7
|
-7
|
-7
|
|
Belgium
|
10
|
10
|
10
|
10
|
10
|
10
|
10
|
10
|
10
|
10
|
10
|
8
|
|
Bhutan
|
-10
|
-10
|
-10
|
-10
|
-10
|
-10
|
-10
|
-10
|
-10
|
-10
|
-10
|
-6
|
|
Bolivia
|
-4
|
-3
|
-3
|
-4
|
-7
|
-7
|
8
|
9
|
9
|
9
|
9
|
8
|
|
Brazil
|
5
|
5
|
5
|
-9
|
-9
|
-4
|
-3
|
7
|
8
|
8
|
8
|
8
|
|
Bulgaria
|
-7
|
-7
|
-7
|
-7
|
-7
|
-7
|
-7
|
-7
|
8
|
8
|
9
|
9
|
name: whytidy
Why is tidy data important?
Think about trying to plot democracy score across years in the simplest way possible.
- It would be much easier if the data looked like what follows instead so we could put
year on the x-axis and
dem_score on the y-axis.
Tidy is good
|
country
|
year
|
dem_score
|
|
Argentina
|
1962
|
-1
|
|
Armenia
|
1997
|
-6
|
|
Denmark
|
1962
|
10
|
|
Ethiopia
|
2007
|
1
|
|
Finland
|
2007
|
10
|
|
Ireland
|
1992
|
10
|
|
Libya
|
1957
|
-7
|
|
Libya
|
1982
|
-7
|
|
Mexico
|
1977
|
-3
|
|
Mexico
|
1982
|
-3
|
|
Spain
|
1962
|
-7
|
|
Switzerland
|
1982
|
10
|
|
Ukraine
|
1997
|
7
|
Let’s plot it
- Plot the line graph for three countries using
ggplot
dem_score4 <- dem_score_tidy %>%
filter(country %in% c("Pakistan", "Portugal", "Uruguay"))
ggplot(data = dem_score4, mapping = aes(x = year, y = dem_score)) +
geom_line(mapping = aes(color = country))

Tidying
The Life Expectancy by year data
library(readr)
life_exp_df <- read_csv("data/le_mess.csv")
#View(life_exp_df)

Doing the “tidying”/reshaping
library(tidyr)
library(dplyr)
(life_exp_tidy <- life_exp_df %>%
gather(key = "year", value = "life_exp", -country))
Tidying
World Health Organization TB data (Stata DTA)
library(haven)
who_df <- read_dta("data/who.dta")
#View(who_df)

WHO ugly…
- This data set contains strange variable names that will require us to look up their meaning in the corresponding data dictionary.
–
- What do we know?
country, iso2, and iso3 are redundant and identify the country
year is a variable and it looks like it corresponds to each country
- But what in the world is
new_sp_m014? And the other columns?…
First step
Like before, we can gather these non-country and non-year variables together:
who_tidy <- who_df %>%
gather(new_sp_m014:newrel_f65, key = "key", value = "value")
We can now see what this has done to the data frame:
Data dictionary saves us some…
- The first three letters of entries in the
key column correspond to new or old cases of TB.
- The next two letters (after the
_) correspond to TB type:
rel for relapse, ep for extrapulmonary TB
sn for smear negative, sp for smear positive
- The next letter after the second
_ corresponds to the sex of the TB patient.
- The remaining numbers correspond to age group:
014 for 0 to 14 years
- …
65 for 65 or older
Looking over the entries of key in who_tidy, do you see anything else that doesn’t match the pattern?
It may be easier to remember that the entries of key correspond to column names in who_df:
[1] "country" "iso2" "iso3" "year"
[5] "new_sp_m014" "new_sp_m1524" "new_sp_m2534" "new_sp_m3544"
[9] "new_sp_m4554" "new_sp_m5564" "new_sp_m65" "new_sp_f014"
[13] "new_sp_f1524" "new_sp_f2534" "new_sp_f3544" "new_sp_f4554"
[17] "new_sp_f5564" "new_sp_f65" "new_sn_m014" "new_sn_m1524"
[21] "new_sn_m2534" "new_sn_m3544" "new_sn_m4554" "new_sn_m5564"
[25] "new_sn_m65" "new_sn_f014" "new_sn_f1524" "new_sn_f2534"
[29] "new_sn_f3544" "new_sn_f4554" "new_sn_f5564" "new_sn_f65"
[33] "new_ep_m014" "new_ep_m1524" "new_ep_m2534" "new_ep_m3544"
[37] "new_ep_m4554" "new_ep_m5564" "new_ep_m65" "new_ep_f014"
[41] "new_ep_f1524" "new_ep_f2534" "new_ep_f3544" "new_ep_f4554"
[45] "new_ep_f5564" "new_ep_f65" "newrel_m014" "newrel_m1524"
[49] "newrel_m2534" "newrel_m3544" "newrel_m4554" "newrel_m5564"
[53] "newrel_m65" "newrel_f014" "newrel_f1524" "newrel_f2534"
[57] "newrel_f3544" "newrel_f4554" "newrel_f5564" "newrel_f65"
A fix using stringr
You can replace all of the entries in key that contained newrel with new_rel via
library(stringr)
library(dplyr)
who_tidy <- who_tidy %>%
mutate(key = str_replace(
string = key,
pattern = "newrel",
replacement = "new_rel")
)
Pulling apart variables
The entry new_sp_m014 is actually four different variables. Use the separate function to pull them apart:
who_tidy <- who_tidy %>%
separate(col = key, into = c("new", "type", "sexage"), sep = "_")
who_tidy
One more pull apart
- We need to pull
sexage into two different variables.
- If you use
?separate, you’ll see that the following is an option:
(who_tidy <- who_tidy %>%
separate(col = sexage, into = c("sex", "age"), sep = 1))
Final cleaning
iso2 and iso3 are redundant if we have country
new is constant since this only has new cases of TB
- Let’s just ignore missing values here
- We also know that
value is actually cases so we can rename that column.
who_tidy <- who_tidy %>% select(-iso2, -iso3, -new) %>%
na.omit() %>% rename("cases" = value)
head(who_tidy, 5)
The power of the %>% (pipe)
Everything we did above can be chained into one sequence:
who_tidy <- who_df %>%
gather(new_sp_m014:newrel_f65, key = "key", value = "value") %>%
mutate(key = str_replace(key, pattern = "newrel",
replacement = "new_rel")) %>%
separate(col = key, into = c("new", "type", "sexage"), sep = "_") %>%
separate(col = sexage, into = c("sex", "age"), sep = 1) %>%
select(-iso2, -iso3, -new) %>%
na.omit() %>%
rename("cases" = value)
BONUS
A Gapminder tidy dataset read in from a Google Sheet!
- I’ve updated the
gapminder data set available in the gapminder R data package by Jenny Bryan here. Jenny provides instructions for recreating the data.
BONUS
- You can download the updated data from Google Sheets by running the following in R:
# Link is https://docs.google.com/spreadsheets/d/18L5ZiXd1CQ97XWSqb04x1YQ4ncsEOdR7eHzgX0ZIuPA/edit?usp=sharing
library(googlesheets)
updated_gap <- gs_key("18L5ZiXd1CQ97XWSqb04x1YQ4ncsEOdR7eHzgX0ZIuPA") %>%
gs_read()
- A script going through the steps to take the “messy” original Gapminder.org files and turn them into this tidy dataset is available here.
Practice (after the bootcamp)
Try to tidy the other data sets you downloaded and imported or other data sets you have!
name: model class: inverse, center, middle
Data Modeling
Modeling
- Experience with
ggplot2 package and knowledge of the Grammar of Graphics primes students for modeling
- Use of the
broom package to unpack regression output into a tidy format
1. ggplot2 Primes Regression
Example:
- All Alaskan Airlines and Frontier flights leaving NYC in 2013
- We want to study the relationship between temperature and departure delay
- For summer (June, July, August) and non-summer months separately
Involves four variables:
carrier, temp, dep_delay, summer
1. ggplot2 Primes Regression
flights_subset <- flights %>%
filter(carrier == "AS" | carrier == "F9") %>%
left_join(weather, by=c("year", "month", "day", "hour", "origin")) %>%
filter(dep_delay < 250) %>%
mutate(summer = ifelse(month == 6 | month == 7 | month == 8, "Summer Flights", "Non-Summer Flights"))
ggplot(data = flights_subset,
mapping = aes(x = temp, y = dep_delay, color = carrier)) +
geom_point() +
geom_smooth(method = "lm", se = FALSE) +
facet_wrap(~ summer)

1. ggplot2 Primes Regression
Why? Dig deeper into data. Look at origin and dest variables as well:
flights_subset %>%
group_by(carrier, origin, dest) %>%
summarise(`Number of Flights` = n())
2. broom Package
- The
broom package takes the messy output of built-in modeling functions in R, such as lm, nls, or t.test, and turns them into tidy data frames.
- Fits in with
tidyverse ecosystem
- This works for many R data types!
2. broom Package
In our case, broom functions take lm objects as inputs and return the following in tidy format!
tidy(): regression output table
augment(): point-by-point values (fitted values, residuals, predicted values)
glance(): scalar summaries like \(R^2\) ,
2. broom Package
Example
library(tidyverse)
library(nycflights13)
library(knitr)
library(broom)
set.seed(2017)
# Load Alaska data, deleting rows that have missing departure delay
# or arrival delay data
alaska_flights <- flights %>%
filter(carrier == "AS") %>%
filter(!is.na(dep_delay) & !is.na(arr_delay)) %>%
sample_n(50)
# Exploratory Data Analysis-----------------------------------------
# Plot of sample of points:
ggplot(data = alaska_flights, mapping = aes(x = dep_delay, y = arr_delay)) +
geom_point()

# Correlation coefficient:
alaska_flights %>% summarize(correl = cor(dep_delay, arr_delay))
# Add regression line
ggplot(data = alaska_flights, mapping = aes(x = dep_delay, y = arr_delay)) +
geom_point() +
geom_smooth(method = "lm", se = FALSE, color = "red")

# Fit Regression and Study Output with broom Package-------------------
# Fit regression
options(scipen = 6) # Set scientific notation
delay_fit <- lm(formula = arr_delay ~ dep_delay, data = alaska_flights)
# 1. broom::tidy() regression table with confidence intervals
# and no p-value stars
regression_table <- delay_fit %>%
tidy(conf.int = TRUE)
regression_table
# 2. broom::augment() for point-by-point values
regression_points <- delay_fit %>%
augment() %>%
select(arr_delay, dep_delay, .fitted, .resid)
regression_points
# and for prediction
new_flights <- data_frame(dep_delay = c(25, 30, 15))
delay_fit %>%
augment(newdata = new_flights)
# 3. broom::glance() scalar summaries of regression
regression_summaries <- delay_fit %>%
glance()
regression_summaries
# Residual Analysis------------------------------------------------------
ggplot(data = regression_points, mapping = aes(x = .resid)) +
geom_histogram(binwidth=10, color = "white") +
geom_vline(xintercept = 0, color = "blue")

ggplot(data = regression_points, mapping = aes(x = .fitted, y = .resid)) +
geom_point() +
geom_abline(intercept = 0, slope = 0, color = "blue")

ggplot(data = regression_points, mapping = aes(sample = .resid)) +
stat_qq()

class: center, middle, inverse name: rmarkdown
Data Communicating
What is Markdown?
- A “plaintext formatting syntax”
- Type in plain text, render to more complex formats
- One step beyond writing a
txt file
- Render to HTML, PDF, DOCX, etc. using Pandoc
What does it look like?
.left-column[
# Header 1
## Header 2
Normal paragraphs of text go here.
**I'm bold**
[links!](http://rstudio.com)
* Unordered
* Lists
And Tables
---- -------
Like This
]
.right-column[
]
What is R Markdown?
- “Literate programming”
- Embed R code in a Markdown document
- Renders textual output along with graphics
.left-column[
```{r chunk1}
library(ggplot2)
library(nycflights13)
pdx_flights <- flights %>%
filter(dest == "PDX", month == 5)
nrow(pdx_flights)
```
```{r chunk2}
ggplot(data = pdx_flights,
mapping = aes(x = arr_delay,
y = dep_delay)) +
geom_point()
```
]
.right-column[
[1] 88
]
Practice
Turn a statistical analysis you have conducted into an R Markdown document.
class: middle
LS0tCnRpdGxlOiBQdXR0aW5nIHRoZSBbYFJgXSgpIGluIFtgUmBdKCllZWQgYW5kIDxicj4gaW4gTGV3aXMgYW5kIENsYVtgUmBdKClrCmF1dGhvcjogIkNoZXN0ZXIgSXNtYXkgPGJyPjxicj4gR2l0SHViOiBbYGlzbWF5Y2BdKGh0dHBzOi8vZ2l0aHViLmNvbS9pc21heWMpIDxicj4gVHdpdHRlcjogIFtgQG9sZF9tYW5fY2hlc3RlcmBdKGh0dHBzOi8vdHdpdHRlci5jb20vb2xkX21hbl9jaGVzdGVyKSIKZGF0ZTogMjAxNy0wNS0yNSAmIDIwMTctMDUtMjYgPGJyPjxicj4gQm9vdGNhbXAgd2Vic2l0ZSBhdCA8aHR0cDovL2JpdC5seS9yYm9vdGNhbXAxNz4gPGJyPiBTbGlkZXMgYXZhaWxhYmxlIGF0IDxodHRwOi8vYml0Lmx5L3Jib290Y2FtcDE3LXNsaWRlcz4Kb3V0cHV0OiAKICAgIGh0bWxfZG9jdW1lbnQ6CiAgICAgIHRvYzogdHJ1ZQogICAgICB0b2NfZmxvYXQ6IHRydWUKICAgICAgdG9jX2RlcHRoOiAxCiAgICAgIHRoZW1lOiBjb3NtbwogICAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICAgIGRmX3ByaW50OiBwYWdlZAogICAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCi0tLQoKbmFtZTogdG9jCgojIFRhYmxlIG9mIENvbnRlbnRzCgotIFtEYXRhIFZpel0oI3ZpeikKLSBbRGF0YSBXcmFuZ2xpbmddKCN3cmFuZ2xlKQotIFtEYXRhIEltcG9ydGluZ10oI2ltcG9ydCkKLSBbRGF0YSBUaWR5aW5nXSgjdGlkeSkKLSBbRGF0YSBNb2RlbGluZ10oI21vZGVsKQotIFtEYXRhIENvbW11bmljYXRpbmddKCNybWFya2Rvd24pCgoKLS0tCgpjbGFzczogaW52ZXJzZSwgY2VudGVyLCBtaWRkbGUKCjwhLS0gV3JpdGUgc2xpZGUgbGluayBvbiB3aGl0ZWJvYXJkIC0tPgoKYGBge3IgaW5jbHVkZT1GQUxTRX0KI29wdGlvbnMoc2VydnIuZGFlbW9uID0gVFJVRSkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkobW9zYWljKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkob2tjdXBpZGRhdGEpCmxpYnJhcnkoa25pdHIpCmZpbHRlciA8LSBkcGx5cjo6ZmlsdGVyCmtuaXRyOjpvcHRzX2NodW5rJHNldCh3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTQuNSwgCiAgY29tbWVudD1OQSwgcm93cy5wcmludD0xNikKdGhlbWVfc2V0KHRoZW1lX2dyYXkoYmFzZV9zaXplID0gMjQpKQpgYGAKCiMgUHJlLWJvb3RjYW1wIEhXCgojIyBUYWxrIGFib3V0IHlvdXIgYW5hbHlzaXMgb24gdGhlIDxicj4gYHdlYXRoZXJgIGRhdGEgPGJyPiBpbiBncm91cHMgb2YgMi0zCgotLS0KCiMjIExldCdzIGdldCBpdCBhbGwgb3V0IHRoZXJlCgojIyBXaGVuIHlvdSB0aGluayBvZiBSIHdoYXQgY29tZXMgdG8gbWluZD8KCi0tLQoKbmFtZTogd2h5cgoKIyMgV2h5IGFyZSB5b3UgaGVyZSB3YW50aW5nIHRvIGxlYXJuIFI/CgotIH5+QmVjYXVzZSB5b3UgZW5qb3kgcGFydGFraW5nIGluIFtTY2hhZGVuZnJldWRlXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9TY2hhZGVuZnJldWRlKX5+Cgo8Y2VudGVyPgo8aW1nIHNyYz0iZmlndXJlL2dvb2dsZV9zY2hvbGFyLnBuZyIgc3R5bGU9IndpZHRoOiA3MDBweDsiLz4KPC9jZW50ZXI+CgotLS0KCiMjIFdoeSBzaG91bGQgeW91IGxlYXJuIFI/CgotIFIgaXMgZnJlZSwgUiBpbXByb3ZlcywgUiBoYXMgZXhpc3RlZCBmb3IgNDArIHllYXJzCi0gU3R1ZGVudHMgY2FuIHNob3cgd2hhdCB0aGV5IGhhdmUgbGVhcm5lZCB0byBhIHBvdGVudGlhbCBlbXBsb3llciBlYXNpbHkKLSBUaGUgc3VwcG9ydCBzeXN0ZW0gZm9yIFIgaXMgYWN0dWFsbHkgbXVjaCBiZXR0ZXIgdGhhbiBzb21lIHBlb3BsZSBzYXkKCgotLS0KCiMjIEJ1dCBhcyBhIHByb2Zlc3Nvciwgd2h5IHNob3VsZCB5b3UgbGVhcm4gUj8KCi0gUiBhbmQgUiBNYXJrZG93biB3aWxsIHNhdmUgeW91IFRPTlMgb2YgdGltZS4gTG9uZyB0ZXJtIHRoaW5raW5nIGlzIGtleS4KICAgIC0gWW91IGNhbiBlYXNpbHkgdHdlYWsgeW91ciBjb2RlIGlmIHlvdSBuZWVkIHRvIGRvIGFub3RoZXIgYW5hbHlzaXMKICAgIC0gUmVtZW1iZXJpbmcgd2hhdCBkcm9wLWRvd24gbWVudSBzb21lIHRoaW5nIGlzIGluIHR3byB5ZWFycyBmcm9tIG5vdyBpbiBhIGRpZmZlcmVudCBwcm9ncmFtIHdpbGwgYmUgaGFyZAogICAgLSBSZW1lbWJlcmluZyB0byBjb3B5LWFuZC1wYXN0ZSB5b3VyIHVwZGF0ZWQgcGxvdHMvYW5hbHlzaXMgaW50byB5b3VyIHdvcmQgcHJvY2Vzc29yIGlzIGEgcGFpbiBhbmQgZXJyb3IgcHJvbmUKCi0tLQoKIyMgQnV0IGFzIGEgcHJvZmVzc29yLCB3aHkgc2hvdWxkIHlvdSBsZWFybiBSPwogICAgCjxjZW50ZXI+CjxpbWcgc3JjPSJmaWd1cmUvdHdlZXQuanBnIiBzdHlsZT0id2lkdGg6IDcwMHB4OyIvPgo8L2NlbnRlcj4KCi0tLQoKY2xhc3M6IGludmVyc2UsIGNlbnRlciwgbWlkZGxlCgojIERFTU8gaW4gUlN0dWRpbyA8YnI+IHdpdGggUiBNYXJrZG93bgoKLS0tCgpjbGFzczogY2VudGVyLCBtaWRkbGUKCiMjIEFuYWxvZ3kKClIgICAgICAgICAgICB8ICBSU3R1ZGlvIHwgIERhdGFDYW1wCjotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tOnw6LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLTp8Oi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS06CjxpbWcgc3JjPSJmaWd1cmUvZW5naW5lLmpwZyIgYWx0PSJEcmF3aW5nIiBzdHlsZT0id2lkdGg6IDM1MHB4OyIvPiAgfCAgPGltZyBzcmM9ImZpZ3VyZS9kYXNoYm9hcmQuanBnIiBhbHQ9IkRyYXdpbmciIHN0eWxlPSJ3aWR0aDogMzUwcHg7Ii8+ICB8ICA8aW1nIHNyYz0iZmlndXJlL2luc3RydWN0b3IuanBnIiBhbHQ9IkRyYXdpbmciIHN0eWxlPSJ3aWR0aDogMzUwcHg7Ii8+CgotLS0KCiMjIFdoYXQgdGhpcyBib290Y2FtcCBpcwoKIVtdKGh0dHBzOi8vb3VyY29kaW5nY2x1Yi5naXRodWIuaW8vaW1nL3RpZHl2ZXJzZS5wbmcpCgotIERlc2lnbmVkIGZvciBhbGwgbGV2ZWxzIG9mIGtub3dsZWRnZSBhbmQgYmFja2dyb3VuZAoKLS0tCgojIyBXaGF0IHRoaXMgYm9vdGNhbXAgaXMgbm90CgotIEEgdGhvcm91Z2ggZGV2ZWxvcG1lbnQgb2YgbWFjaGluZSBsZWFybmluZyA8YnI+IHRlY2huaXF1ZXMgYXBwbGllZCB0byBiaWcgZGF0YQoKLS0KCi0gQSBkaXNjdXNzaW9uIG9uIHRoZSByb2xlIG9mIF9wXy12YWx1ZXMgaW4gc2NpZW5jZQoKLS0KCi0gQSB0dXRvcmlhbCBvbiBob3cgdG8gd29yayB3aXRoIGJhc2UgUiBzdWJzZXR0aW5nIGFuZCBiYXNlIFIgZ3JhcGhpY3MgCgotLS0KCiMjIFdoYXQgSSBob3BlIHlvdSdsbCBsZWFybgoKLSBUaGF0IFIgaXMgbm90IGFzIHNjYXJ5IGFzIGl0IHVzZWQgdG8gYmUuICAKCi0tCgotIExlYXJuaW5nIGhvdyB0byBHb29nbGUgaXMgYW4gaW5jcmVkaWJseSB2YWx1YWJsZSBza2lsbC4KCi0tCgotIFRoYXQgaGF2aW5nIHN0dWRlbnRzIHR1cm4gaW4gYXNzaWdubWVudHMgdXNpbmcgUiBzY3JpcHRzIGFuZCBSIE1hcmtkb3duIHByb3ZpZGVzIGFuIGVmZmljaWVudCB3YXkgdG8gY2hlY2sgdGhlaXIgd29yayBhbmQgdGhlaXIgYW5hbHlzZXMgZWFzaWx5LgoKLS0tCgojIyBXaGF0IEkgaG9wZSB5b3UnbGwgbGVhcm4KCi0gVGhhdCB0aGUgUiBwYWNrYWdlcyB5b3Ugd2lsbCB1c2UgaW4gdGhpcyB3b3Jrc2hvcCBhcmUgdGhlIHNhbWUgb25lcyB0aGF0IGFyZSB1c2VkIGJ5IHNjaWVudGlzdHMgYW5kIGdyYWR1YXRlIHByb2dyYW1zIGFsbCBvdmVyIHRoZSB3b3JsZAoKLS0KCi0gVGhhdCB0ZWFjaGluZyBzdHVkZW50cyBob3cgdG8gdXNlIG9wZW4tc291cmNlIHRvb2xzIGlzIHdoYXQgaXMgYmVzdCBmb3IgdGhlbSBsb25nIHRlcm0KCi0tCgotIFRoYXQgc3R1ZGVudHMgd2l0aCBubyBwcm9ncmFtbWluZyBiYWNrZ3JvdW5kIGNhbiBkbyBncmVhdCB0aGluZ3MgaW4gb25seSBhIGZldyB3ZWVrcwogICAgLSBbU29jaW9sb2d5L0NyaW1pbmFsIEp1c3RpY2UgbWFqb3JzIGF0IFBhY2lmaWMgVS5dKGh0dHBzOi8vaXNtYXljLmdpdGh1Yi5pby9zb2MzMDFfczIwMTcvZ3JvdXAtcHJvamVjdHMvaW5kZXguaHRtbCkKICAgIC0gW0Egd2lkZSByYW5nZSBvZiBzdHVkZW50cyBhdCBNaWRkbGVidXJ5IENvbGxlZ2VdKGh0dHBzOi8vcnVkZWJveWJlcnQuZ2l0aHViLmlvL01BVEgxMTYvUFMvZmluYWxfcHJvamVjdC9maW5hbF9wcm9qZWN0X291dGxpbmUuaHRtbCkKCi0tLQoKIyMgUGllY2VzIG9mIGFkdmljZQoKPGNlbnRlcj4KPGEgaHJlZj0iaHR0cDovL2dpcGh5LmNvbS9naWZzL3Bvb2wtZGl2aW5nLXN5bmNocm9uaXplZC1zd2ltbWluZy1wRFd0d0s3RDJJbEZ1Ij48aW1nIHNyYz0iZmlndXJlL2dpcGh5Mi5naWYiIHN0eWxlPSJ3aWR0aDogMzAwcHg7Ii8+PC9hPgo8L2NlbnRlcj4KCi0gU2NhZmZvbGQgJiBzdXBwb3J0IGFzIGEgZm9yZWlnbiBsYW5ndWFnZXMgZG8KCi0tCgotIFRvIGJlIGFibGUgdG8gdXNlIFIgKGFuZCByZWFsbHkgYW55IG90aGVyIGxhbmd1YWdlKSwgc3R1ZGVudHMgbmVlZCBtb3JlIHRoYW4gYSBmZXcgYXNzaWdubWVudHMgYW5kIG1vcmUgdGhhbiBhIHdlZWtseSBsYWIKCi0tCgotIE1ha2UgdXNlIG9mIFJTdHVkaW8gUHJvamVjdHMgKHN0dWRlbnRzIGhhdmUgYSByZWFsbHkgaGFyZCB0aW1lIG5hdmlnYXRpbmcgZGlyZWN0b3J5IHN0cnVjdHVyZXMpCgoKLS0tCgojIyBQaWVjZXMgb2YgYWR2aWNlCgojIyMgTXkgb3BpbmlvbgoKLSBIYXZlIHN0dWRlbnRzIHdvcmsgb24gd3JpdGluZyB0aGVpciBjb2RlIGluIFIgc2NyaXB0IGZpbGVzIGFuZCBkb2N1bWVudGluZyB0aGVpciBlcnJvcnMKICAgIC0gVGhpcyBpcyB0aGUgc2FtZSB3b3JrZmxvdyB0aGF0IERhdGFDYW1wIHVzZXMKCi0tCgotIFNob3cgc3R1ZGVudHMgW1IgTWFya2Rvd24gYWZ0ZXIgYSBmZXcgd2Vla3NdKGh0dHBzOi8vaXNtYXljLmdpdGh1Yi5pby9zb2MzMDFfczIwMTcvc2NoZWR1bGUvKSBvZiB3b3JraW5nIHdpdGggdGhlIHNjcmlwdCBmaWxlCiAgICAtIEkndmUgZm91bmQgaXQgaXMgaGFyZCBmb3Igc3R1ZGVudHMgdG8gbGVhcm4gUiBhbmQgUiBNYXJrZG93biBmcm9tIHRoZSBzdGFydAogICAgLSBCZXR0ZXIgdG8gaGF2ZSB0aGVtIHVzZSBSIE1hcmtkb3duIGluIGdyb3VwcyBpbml0aWFsbHkKCgotLS0KCgpjbGFzczogaW52ZXJzZSwgY2VudGVyLCBtaWRkbGUKCiMgUiBEYXRhIFR5cGVzCgotLS0KCiMjIFRoZSBiYXJlIG1pbmltdW0gbmVlZGVkIGZvciB1bmRlcnN0YW5kaW5nIHRvZGF5CgpWZWN0b3IvdmFyaWFibGUKICAtIFR5cGUgb2YgdmVjdG9yIChgaW50YCwgYG51bWAsIGBjaHJgLCBgbGdsYCwgYGRhdGVgKQoKLS0KCkRhdGEgZnJhbWUKICAtIFZlY3RvcnMgb2YgKHBvdGVudGlhbGx5KSBkaWZmZXJlbnQgdHlwZXMKICAtIEVhY2ggdmVjdG9yIGhhcyB0aGUgc2FtZSBudW1iZXIgb2Ygcm93cwoKLS0tCgojIyBUaGUgYmFyZSBtaW5pbXVtIG5lZWRlZCBmb3IgdW5kZXJzdGFuZGluZyB0b2RheQoKYGBge3IgZXZhbD1GQUxTRX0KbGlicmFyeSh0aWJibGUpCmxpYnJhcnkobHVicmlkYXRlKQpleDEgPC0gZGF0YV9mcmFtZSgKICAgIHZlYzEgPSBjKDE5ODAsIDE5OTAsIDIwMDAsIDIwMTApLAogICAgdmVjMiA9IGMoMUwsIDJMLCAzTCwgNEwpLAogICAgdmVjMyA9IGMoImxvdyIsICJsb3ciLCAiaGlnaCIsICJoaWdoIiksCiAgICB2ZWM0ID0gYyhUUlVFLCBGQUxTRSwgRkFMU0UsIEZBTFNFKSwKICAgIHZlYzUgPSB5bWQoYygiMjAxNy0wNS0yMyIsICIxNzc2LzA3LzA0IiwgIjE5ODMtMDUvMzEiLCAiMTkwOC8wNC0wMSIpKQogICkKZXgxCmBgYAoKLS0KCmBgYHtyIGVjaG89RkFMU0V9CmxpYnJhcnkodGliYmxlKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKZXgxIDwtIGRhdGFfZnJhbWUoCiAgICB2ZWMxID0gYygxOTgwLCAxOTkwLCAyMDAwLCAyMDEwKSwKICAgIHZlYzIgPSBjKDFMLCAyTCwgM0wsIDRMKSwKICAgIHZlYzMgPSBjKCJsb3ciLCAibG93IiwgImhpZ2giLCAiaGlnaCIpLAogICAgdmVjNCA9IGMoVFJVRSwgRkFMU0UsIEZBTFNFLCBGQUxTRSksCiAgICB2ZWM1ID0geW1kKGMoIjIwMTctMDUtMjMiLCAiMTc3Ni83LzA0IiwgIjE5ODMtNS8zMSIsICIxOTA4LzA0LTEiKSkKICApCmV4MQpgYGAKICAKLS0tCgpjbGFzczogY2VudGVyLCBtaWRkbGUgIAogIAojIyBXZWxjb21lIHRvIHRoZSBbdGlkeXZlcnNlXShodHRwczovL2Jsb2cucnN0dWRpby5vcmcvMjAxNi8wOS8xNS90aWR5dmVyc2UtMS0wLTAvKSEKICAKVGhlIGB0aWR5dmVyc2VgIGlzIGEgY29sbGVjdGlvbiBvZiBSIHBhY2thZ2VzIHRoYXQgc2hhcmUgY29tbW9uIHBoaWxvc29waGllcyBhbmQgYXJlIGRlc2lnbmVkIHRvIHdvcmsgdG9nZXRoZXIuIDxicj48YnI+IAogIAo8YSBocmVmPSJodHRwOi8vdGlkeXZlcnNlLnRpZHl2ZXJzZS5vcmcvbG9nby5wbmciPjxpbWcgc3JjPSJmaWd1cmUvdGlkeXZlcnNlLnBuZyIgc3R5bGU9IndpZHRoOiAyMDBweDsiLz48YT4KCi0tLQoKCiMjIEJlZ2lubmluZyBzdGVwcwoKRnJlcXVlbnRseSB0aGUgZmlyc3QgdGhpbmcgdG8gZG8gd2hlbiBnaXZlbiBhIGRhdGFzZXQgaXMgdG8KLSBpZGVudGlmeSB0aGUgb2JzZXJ2YXRpb25hbCB1bml0LAotIHNwZWNpZnkgdGhlIHZhcmlhYmxlcywKLSBnaXZlIHRoZSB0eXBlcyBvZiB2YXJpYWJsZXMgeW91IGFyZSBwcmVzZW50ZWQgd2l0aCwgYW5kCi0gY2hlY2sgdGhhdCB0aGUgZGF0YSBpcyA8dT50aWR5PC91Pi4gKFRPIENPTUUpCgpUaGlzIHdpbGwgaGVscCB3aXRoIAotIGNob29zaW5nIHRoZSBhcHByb3ByaWF0ZSBwbG90LCAKLSBzdW1tYXJpemluZyB0aGUgZGF0YSwgYW5kIAotIHVuZGVyc3RhbmRpbmcgd2hpY2ggaW5mZXJlbmNlcy9tb2RlbHMgY2FuIGJlIGFwcGxpZWQuCgotLS0KCmNsYXNzOiBpbnZlcnNlLCBjZW50ZXIsIG1pZGRsZQpuYW1lOiB2aXoKCgojIERhdGEgVmlzdWFsaXphdGlvbgoKPGEgaHJlZj0iaHR0cDovL2dpdHNlbnNlLmdpdGh1Yi5pby9pbWFnZXMvd2VhbHRoLmdpZiI+PGltZyBzcmM9ImZpZ3VyZS93ZWFsdGguZ2lmIiBzdHlsZT0id2lkdGg6IDc3MHB4OyIvPjwvYT4KCkluc3BpcmVkIGJ5IFtIYW5zIFJvc2xpbmddKGh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9amJrU1JMWVNvam8pCgotLS0KCmBgYHtyIGVjaG89RkFMU0UsZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTAsIGZpZy5hbGlnbj0nY2VudGVyJ30KbGlicmFyeShnYXBtaW5kZXIpCm9wdGlvbnMoc2NpcGVuID0gOTkpCiNnYXBfd2l0aF9jb2xvcnMgPC0KIyAgZGF0YS5mcmFtZShnYXBtaW5kZXIsCiMgICAgICAgICAgICAgY2MgPSBJKGNvdW50cnlfY29sb3JzW21hdGNoKGdhcG1pbmRlciRjb3VudHJ5LAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lcyhjb3VudHJ5X2NvbG9ycykpXSkpCgpnYXBtaW5kZXIgJT4lIGZpbHRlcih5ZWFyID09IDE5OTIpICU+JQogIGdncGxvdChhZXMoeCA9IGxvZyhnZHBQZXJjYXAsIGJhc2UgPSAxMCksIHkgPSBsaWZlRXhwLCBjb2xvciA9IGNvbnRpbmVudCwKICAgICAgICAgICAgIHNpemUgPSBwb3ApKSArCiAgZ2VvbV9wb2ludCgpICsgeGxhYignR3Jvc3MgRG9tZXN0aWMgUHJvZHVjdCAobG9nIHNjYWxlKScpICsgeWxhYignTGlmZSBFeHBlY3RhbmN5IGF0IGJpcnRoICh5ZWFycyknKSArIGdndGl0bGUoIkdhcG1pbmRlciBmb3IgMTk5MiIpCgojKwojICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gZ2FwbWluZGVyOjpjb250aW5lbnRfY29sb3JzKQpgYGAKCgotIFdoYXQgYXJlIHRoZSB2YXJpYWJsZXMgaGVyZT8KLSBXaGF0IGlzIHRoZSBvYnNlcnZhdGlvbmFsIHVuaXQ/Ci0gSG93IGFyZSB0aGUgdmFyaWFibGVzIG1hcHBlZCB0byBhZXN0aGV0aWNzPwoKLS0tCgoKIyMgR3JhbW1hciBvZiBHcmFwaGljcwoKLmxlZnQtY29sdW1uWwpXaWxraW5zb24gKDIwMDUpIGxhaWQgb3V0IHRoZSBwcm9wb3NlZCAiR3JhbW1hciBvZiBHcmFwaGljcyIKXQoKLnJpZ2h0LWNvbHVtblsKPGEgaHJlZj0iaHR0cDovL3d3dy5wb3dlbGxzLmNvbS9ib29rL3RoZS1ncmFtbWFyLW9mLWdyYXBoaWNzLTk3ODAzODcyNDU0NDciPjxpbWcgc3JjPSJmaWd1cmUvZ3JhcGhpY3MuanBnIiBzdHlsZT0id2lkdGg6IDMwMHB4OyI+PC9hPgpdCgotLS0KCiMjIEdyYW1tYXIgb2YgR3JhcGhpY3MgaW4gUgoKLmxlZnQtY29sdW1uWwpXaWNraGFtIGltcGxlbWVudGVkIHRoZSBncmFtbWFyIGluIFIgaW4gdGhlIGBnZ3Bsb3QyYCBwYWNrYWdlCl0KCi5yaWdodC1jb2x1bW5bCjxhIGhyZWY9Imh0dHA6Ly93d3cucG93ZWxscy5jb20vYm9vay9nZ3Bsb3QyLWVsZWdhbnQtZ3JhcGhpY3MtZm9yLWRhdGEtYW5hbHlzaXMtOTc4MzMxOTI0Mjc1MC82OC00MjgiPjxpbWcgc3JjPSJmaWd1cmUvZ2dwbG90Mi5qcGciIHN0eWxlPSJ3aWR0aDogMzAwcHg7Ij48L2E+Cl0KCi0tLQoKIyMgR3JhbW1hciBvZiBHcmFwaGljcyBlbHNld2hlcmUKCi0gW01ha2UgcGxvdHMgb25saW5lIHdpdGggcGxvdGx5XShodHRwczovL3Bsb3QubHkvKQoKLSBbTGVsYW5kIFdpbGtpbnNvbl0oaHR0cHM6Ly9yZXNlYXJjaC50YWJsZWF1LmNvbS91c2VyL2xlbGFuZC13aWxraW5zb24pIHdvcmtzIGF0IFtUYWJsZWF1XShodHRwczovL3d3dy50YWJsZWF1LmNvbS8pCgotIFRoZSBHcmFtbWFyIG9mIEdyYXBoaWNzIHByb3ZpZGVzIGEgdGhlb3JldGljYWwgZnJhbWV3b3JrIGZvciBidWlsZGluZyBhbmQgZGVjaXBoZXJpbmcgc3RhdGlzdGljYWwgZ3JhcGhpY3MKCi0tLQoKY2xhc3M6IGNlbnRlciwgbWlkZGxlCgojIFdoYXQgaXMgYSBzdGF0aXN0aWNhbCBncmFwaGljPwotLQoKIyMgQSBgbWFwcGluZ2Agb2YgPGJyPiBgZGF0YWAgdmFyaWFibGVzCi0tCgojIyB0byA8YnI+IGBhZXMoKWB0aGV0aWMgYXR0cmlidXRlcwoKLS0KIyMgb2YgPGJyPiBgZ2VvbV9gZXRyaWMgb2JqZWN0cy4KCi0tLQoKY2xhc3M6IGludmVyc2UsIGNlbnRlciwgbWlkZGxlCgojIyBCYWNrIHRvIGJhc2ljcwoKLS0tCgojIyMgQ29uc2lkZXIgdGhlIGZvbGxvd2luZyBkYXRhIGluIHRpZHkgZm9ybWF0OgoKYGBge3J9CnNpbXBsZV9leCA8LQogIGRhdGFfZnJhbWUoCiAgICBBID0gYygxOTgwLCAxOTkwLCAyMDAwLCAyMDEwKSwKICAgIEIgPSBjKDEsIDIsIDMsIDQpLAogICAgQyA9IGMoMywgMiwgMSwgMiksCiAgICBEID0gYygibG93IiwgImxvdyIsICJoaWdoIiwgImhpZ2giKQogICkKc2ltcGxlX2V4CmBgYAoKPCEtLSBDb3B5IHRvIGNoYWxrYm9hcmQvd2hpdGVib2FyZCAtLT4KCi0tLQoKIyMjIENvbnNpZGVyIHRoZSBmb2xsb3dpbmcgZGF0YSBpbiB0aWR5IGZvcm1hdDoKCmBgYHtyIGVjaG89RkFMU0V9CnNpbXBsZV9leCAlPiUga25pdHI6OmthYmxlKGZvcm1hdD0iaHRtbCIpCmBgYAoKCi0gU2tldGNoIHRoZSBncmFwaGljcyBiZWxvdyBvbiBwYXBlciwgd2hlcmUgdGhlIGB4YC1heGlzIGlzIHZhcmlhYmxlIGBBYCBhbmQgdGhlIGB5YC1heGlzIGlzIHZhcmlhYmxlIGBCYAoKMS4gPHNtYWxsPkEgc2NhdHRlciBwbG90PC9zbWFsbD4KMS4gPHNtYWxsPkEgc2NhdHRlciBwbG90IHdoZXJlIHRoZSBgY29sb3JgIG9mIHRoZSBwb2ludHMgY29ycmVzcG9uZHMgdG8gYERgPC9zbWFsbD4KMS4gPHNtYWxsPkEgc2NhdHRlciBwbG90IHdoZXJlIHRoZSBgc2l6ZWAgb2YgdGhlIHBvaW50cyBjb3JyZXNwb25kcyB0byBgQ2A8L3NtYWxsPgoxLiA8c21hbGw+QSBsaW5lIGdyYXBoPC9zbWFsbD4KMS4gPHNtYWxsPkEgbGluZSBncmFwaCB3aGVyZSB0aGUgYGNvbG9yYCBvZiB0aGUgbGluZSBjb3JyZXNwb25kcyB0byBgRGAgd2l0aCBwb2ludHMgYWRkZWQgdGhhdCBhcmUgYWxsIGZvcmVzdGdyZWVuIG9mIHNpemUgNC48L3NtYWxsPgoKLS0tCgojIyBSZXByb2R1Y2luZyB0aGUgcGxvdHMgaW4gPHNtYWxsPmBnZ3Bsb3QyYDwvc21hbGw+CgojIyMgMS4gQSBzY2F0dGVycGxvdAoKYGBge3IsIGV2YWw9RkFMU0V9CmxpYnJhcnkoZ2dwbG90MikKZ2dwbG90KGRhdGEgPSBzaW1wbGVfZXgsIG1hcHBpbmcgPSBhZXMoeCA9IEEsIHkgPSBCKSkgKyAKICBnZW9tX3BvaW50KCkKYGBgCi0tCgpgYGB7ciwgZWNobz1GQUxTRSwgZmlnLmhlaWdodD00LjV9CmdncGxvdChkYXRhID0gc2ltcGxlX2V4LCBhZXMoeCA9IEEsIHkgPSBCKSkgKyAKICBnZW9tX3BvaW50KCkKYGBgCgoKLS0tCgoKIyMgUmVwcm9kdWNpbmcgdGhlIHBsb3RzIGluIDxzbWFsbD5gZ2dwbG90MmA8L3NtYWxsPgoKIyMjIDIuIEEgc2NhdHRlciBwbG90IHdoZXJlIHRoZSBgY29sb3JgIG9mIHRoZSBwb2ludHMgY29ycmVzcG9uZHMgdG8gYGdyb3VwYAoKYGBge3IsIGV2YWw9RkFMU0V9CmxpYnJhcnkoZ2dwbG90MikKZ2dwbG90KGRhdGEgPSBzaW1wbGVfZXgsIG1hcHBpbmcgPSBhZXMoeCA9IEEsIHkgPSBCKSkgKyAKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoY29sb3IgPSBEKSkKYGBgCi0tCgpgYGB7ciwgZWNobz1GQUxTRSwgZmlnLmhlaWdodD00LjV9CmdncGxvdChkYXRhID0gc2ltcGxlX2V4LCBtYXBwaW5nID0gYWVzKHggPSBBLCB5ID0gQikpICsgCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKGNvbG9yID0gRCkpCmBgYAoKCi0tLQoKIyMgUmVwcm9kdWNpbmcgdGhlIHBsb3RzIGluIDxzbWFsbD5gZ2dwbG90MmA8L3NtYWxsPgoKIyMjIDMuIEEgc2NhdHRlciBwbG90IHdoZXJlIHRoZSBgc2l6ZWAgb2YgdGhlIHBvaW50cyBjb3JyZXNwb25kcyB0byBgQ2AKCmBgYHtyLCBldmFsPUZBTFNFfQpsaWJyYXJ5KGdncGxvdDIpCmdncGxvdChkYXRhID0gc2ltcGxlX2V4LCBtYXBwaW5nID0gYWVzKHggPSBBLCB5ID0gQiwgc2l6ZSA9IEMpKSArIAogIGdlb21fcG9pbnQoKQpgYGAKLS0KCmBgYHtyLCBlY2hvPUZBTFNFLCBmaWcuaGVpZ2h0PTQuNX0KZ2dwbG90KGRhdGEgPSBzaW1wbGVfZXgsIG1hcHBpbmcgPSBhZXMoeCA9IEEsIHkgPSBCLCBzaXplID0gQykpICsgCiAgZ2VvbV9wb2ludCgpCmBgYAoKCi0tLQoKIyMgUmVwcm9kdWNpbmcgdGhlIHBsb3RzIGluIDxzbWFsbD5gZ2dwbG90MmA8L3NtYWxsPgoKIyMjIDQuIEEgbGluZSBncmFwaAoKYGBge3IsIGV2YWw9RkFMU0V9CmxpYnJhcnkoZ2dwbG90MikKZ2dwbG90KGRhdGEgPSBzaW1wbGVfZXgsIG1hcHBpbmcgPSBhZXMoeCA9IEEsIHkgPSBCKSkgKyAKICBnZW9tX2xpbmUoKQpgYGAKLS0KCmBgYHtyLCBlY2hvPUZBTFNFLCBmaWcuaGVpZ2h0PTQuNX0KZ2dwbG90KGRhdGEgPSBzaW1wbGVfZXgsIGFlcyh4ID0gQSwgeSA9IEIpKSArIAogIGdlb21fbGluZSgpCmBgYAoKCi0tLQoKIyMgUmVwcm9kdWNpbmcgdGhlIHBsb3RzIGluIDxzbWFsbD5gZ2dwbG90MmA8L3NtYWxsPgoKIyMjIDUuIEEgbGluZSBncmFwaCB3aGVyZSB0aGUgYGNvbG9yYCBvZiB0aGUgbGluZSBjb3JyZXNwb25kcyB0byBgRGAgd2l0aCBwb2ludHMgYWRkZWQgdGhhdCBhcmUgYWxsIGJsdWUgb2Ygc2l6ZSA0LgoKYGBge3IsIGV2YWw9RkFMU0V9CmxpYnJhcnkoZ2dwbG90MikKZ2dwbG90KGRhdGEgPSBzaW1wbGVfZXgsIG1hcHBpbmcgPSBhZXMoeCA9IEEsIHkgPSBCKSkgKyAKICBnZW9tX2xpbmUobWFwcGluZyA9IGFlcyhjb2xvciA9IEQpKSArCiAgZ2VvbV9wb2ludChjb2xvciA9ICJmb3Jlc3RncmVlbiIsIHNpemUgPSA0KQpgYGAKLS0KCmBgYHtyLCBlY2hvPUZBTFNFLCBmaWcuaGVpZ2h0PTR9CmdncGxvdChkYXRhID0gc2ltcGxlX2V4LCBtYXBwaW5nID0gYWVzKHggPSBBLCB5ID0gQikpICsgCiAgZ2VvbV9saW5lKG1hcHBpbmcgPSBhZXMoY29sb3IgPSBEKSkgKwogIGdlb21fcG9pbnQoY29sb3IgPSAiZm9yZXN0Z3JlZW4iLCBzaXplID0gNCkKYGBgCgotLS0KCiMgVGhlIEZpdmUtTmFtZWQgR3JhcGhzIAoKIyMgVGhlIDVORyBvZiBkYXRhIHZpegoKLSBTY2F0dGVycGxvdDogYGdlb21fcG9pbnQoKWAKLSBMaW5lIGdyYXBoOiBgZ2VvbV9saW5lKClgCi0tCgotIEhpc3RvZ3JhbTogYGdlb21faGlzdG9ncmFtKClgCi0gQm94cGxvdDogYGdlb21fYm94cGxvdCgpYAotIEJhciBncmFwaDogYGdlb21fYmFyKClgCgoKLS0tCgpjbGFzczogY2VudGVyLCBtaWRkbGUKCiMjIE1vcmUgYGdncGxvdDJgIGV4YW1wbGVzCgotLS0KCiMjIEhpc3RvZ3JhbQoKYGBge3IgZmlnLmhlaWdodD01LjV9CmxpYnJhcnkobnljZmxpZ2h0czEzKQpnZ3Bsb3QoZGF0YSA9IHdlYXRoZXIsIG1hcHBpbmcgPSBhZXMoeCA9IGh1bWlkKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAyMCwgY29sb3IgPSAiYmxhY2siLCBmaWxsID0gImRhcmtvcmFuZ2UiKQpgYGAKCi0tLQoKIyMgQm94cGxvdCAoYnJva2VuKQoKYGBge3IgZmlnLmhlaWdodD01LjV9CmxpYnJhcnkobnljZmxpZ2h0czEzKQpnZ3Bsb3QoZGF0YSA9IHdlYXRoZXIsIG1hcHBpbmcgPSBhZXMoeCA9IG1vbnRoLCB5ID0gaHVtaWQpKSArCiAgZ2VvbV9ib3hwbG90KCkKYGBgCgotLS0KCgojIyBCb3hwbG90IChhbG1vc3QgZml4ZWQpCgpgYGB7ciBmaWcuaGVpZ2h0PTUuNX0KbGlicmFyeShueWNmbGlnaHRzMTMpCmdncGxvdChkYXRhID0gd2VhdGhlciwgbWFwcGluZyA9IGFlcyh4ID0gbW9udGgsIGdyb3VwID0gbW9udGgsIHkgPSBodW1pZCkpICsKICBnZW9tX2JveHBsb3QoKSAKYGBgCi0tLQoKIyMgQm94cGxvdCAoZml4ZWQpCgpgYGB7ciBmaWcuaGVpZ2h0PTUuNX0KbGlicmFyeShueWNmbGlnaHRzMTMpCmdncGxvdChkYXRhID0gd2VhdGhlciwgbWFwcGluZyA9IGFlcyh4ID0gbW9udGgsIGdyb3VwID0gbW9udGgsIHkgPSBodW1pZCkpICsKICBnZW9tX2JveHBsb3QoKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IDE6MTIpCmBgYAoKLS0tCgojIyBCYXIgZ3JhcGgKCmBgYHtyfQpsaWJyYXJ5KGZpdmV0aGlydHllaWdodCkKZ2dwbG90KGRhdGEgPSBiZWNoZGVsLCBtYXBwaW5nID0gYWVzKHggPSBjbGVhbl90ZXN0KSkgKwogIGdlb21fYmFyKCkKYGBgCgotLS0KCiMjIEhvdyBhYm91dCBvdmVyIHRpbWU/CgotIEhvcCBpbnRvIGBkcGx5cmAKCmBgYHtyfQpsaWJyYXJ5KGRwbHlyKQp5ZWFyX2JpbnMgPC0gYygiJzcwLSc3NCIsICInNzUtJzc5IiwgIic4MC0nODQiLCAiJzg1LSc4OSIsCiAgICAgICAgICAgICAgICInOTAtJzk0IiwgIic5NS0nOTkiLCAiJzAwLScwNCIsICInMDUtJzA5IiwKICAgICAgICAgICAgICAgIicxMC0nMTMiKQpiZWNoZGVsIDwtIGJlY2hkZWwgJT4lCiAgbXV0YXRlKGZpdmVfeWVhciA9IGN1dCh5ZWFyLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgxOTY5LCAyMDE0LCA1KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSB5ZWFyX2JpbnMpKSAlPiUgCiAgbXV0YXRlKGNsZWFuX3Rlc3QgPSBmYWN0b3IoY2xlYW5fdGVzdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygibm93b21lbiIsICJub3RhbGsiLCAibWVuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJkdWJpb3VzIiwgIm9rIikpKQpgYGAKCi0tLQoKIyMgSG93IGFib3V0IG92ZXIgdGltZT8gKFN0YWNrZWQpCgpgYGB7ciBmaWcud2lkdGg9MTF9CmxpYnJhcnkoZml2ZXRoaXJ0eWVpZ2h0KQpsaWJyYXJ5KGdncGxvdDIpCmdncGxvdChkYXRhID0gYmVjaGRlbCwKICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IGZpdmVfeWVhciwgZmlsbCA9IGNsZWFuX3Rlc3QpKSArCiAgZ2VvbV9iYXIoKQpgYGAKCi0tLQoKIyMgSG93IGFib3V0IG92ZXIgdGltZT8gKFNpZGUtYnktc2lkZSkKCmBgYHtyIGZpZy53aWR0aD0xMX0KbGlicmFyeShmaXZldGhpcnR5ZWlnaHQpCmxpYnJhcnkoZ2dwbG90MikKZ2dwbG90KGRhdGEgPSBiZWNoZGVsLAogICAgICAgbWFwcGluZyA9IGFlcyh4ID0gZml2ZV95ZWFyLCBmaWxsID0gY2xlYW5fdGVzdCkpICsKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJkb2RnZSIpCmBgYAoKLS0tCgojIyBIb3cgYWJvdXQgb3ZlciB0aW1lPyAoU3RhY2tlZCBwcm9wb3J0aW9uYWwpCgpgYGB7ciBmaWcud2lkdGg9MTF9CmxpYnJhcnkoZml2ZXRoaXJ0eWVpZ2h0KQpsaWJyYXJ5KGdncGxvdDIpCmdncGxvdChkYXRhID0gYmVjaGRlbCwKICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IGZpdmVfeWVhciwgZmlsbCA9IGNsZWFuX3Rlc3QpKSArCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZmlsbCIsIGNvbG9yID0gImJsYWNrIikKYGBgCgotLS0KCmNsYXNzOiBjZW50ZXIsIG1pZGRsZQoKIyMgVGhlIGB0aWR5dmVyc2VgL2BnZ3Bsb3QyYCBpcyBmb3IgYmVnaW5uZXJzIGFuZCA8YnI+IGZvciBkYXRhIHNjaWVuY2UgcHJvZmVzc2lvbmFscyEKCjxhIGhyZWY9Imh0dHBzOi8vZml2ZXRoaXJ0eWVpZ2h0LmNvbS9mZWF0dXJlcy90aGUtZG9sbGFyLWFuZC1jZW50cy1jYXNlLWFnYWluc3QtaG9sbHl3b29kcy1leGNsdXNpb24tb2Ytd29tZW4vIj48aW1nIHNyYz0iZmlndXJlL2JlY2hkZWwucG5nIiBzdHlsZT0id2lkdGg6IDUwMHB4OyIvPjxhPgoKLS0tCgojIyBQcmFjdGljZQoKUHJvZHVjZSBhcHByb3ByaWF0ZSA1Tkcgd2l0aCBSIHBhY2thZ2UgJiBkYXRhIHNldCBpbiBbIF0sIGUuZy4sIFtgbnljZmxpZ2h0czEzYCAkXHJpZ2h0YXJyb3ckIGB3ZWF0aGVyYF0gCgo8IS0tClRyeSB0byBsb29rIHRocm91Z2ggdGhlIGhlbHAgZG9jdW1lbnRhdGlvbi9Hb29nbGUgdG8gaW1wcm92ZSB5b3VyIHBsb3RzCi0tPgoKMS4gRG9lcyBgYWdlYCBwcmVkaWN0IGByZWNsaW5lX3J1ZGVgPyA8YnI+IFtgZml2ZXRoaXJ0eWVpZ2h0YCAkXHJpZ2h0YXJyb3ckIGBuYS5vbWl0KGZseWluZylgXQoKMi4gRGlzdHJpYnV0aW9uIG9mIGBhZ2VgIGJ5IGBzZXhgIDxicj4gW2Bva2N1cGlkZGF0YWAgJFxyaWdodGFycm93JCBgcHJvZmlsZXNgXQoKMy4gRG9lcyBgYnVkZ2V0YCBwcmVkaWN0IGByYXRpbmdgPyA8YnI+IFtgZ2dwbG90Mm1vdmllc2AgJFxyaWdodGFycm93JCBgbW92aWVzYF0KCjQuIERpc3RyaWJ1dGlvbiBvZiBsb2cgYmFzZSAxMCBzY2FsZSBvZiBgYnVkZ2V0XzIwMTNgIDxicj4gW2BmaXZldGhpcnR5ZWlnaHRgICRccmlnaHRhcnJvdyQgYGJlY2hkZWxgXQoKLS0tCgojIyMgSElOVFMKCmBgYHtyIGVjaG89RkFMU0UsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTEwLjV9CmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KGZpdmV0aGlydHllaWdodCkKbGlicmFyeShnZ3Bsb3QybW92aWVzKQpsaWJyYXJ5KG9rY3VwaWRkYXRhKQoKcDEgPC0gZ2dwbG90KGRhdGEgPSBuYS5vbWl0KGZseWluZyksIG1hcHBpbmcgPSBhZXMoZmlsbCA9IHJlY2xpbmVfcnVkZSwgeCA9IGFnZSkpICsgZ2VvbV9iYXIocG9zaXRpb24gPSAiZmlsbCIpICsgZ2d0aXRsZSgiUHJvYmxlbSAxIikgKyB0aGVtZV9ncmF5KGJhc2Vfc2l6ZSA9IDIwKQoKcDIgPC0gZ2dwbG90KGRhdGEgPSBwcm9maWxlcywgbWFwcGluZyA9IGFlcyh4ID0gc2V4LCB5ID0gYWdlKSkgKwogIGdlb21fYm94cGxvdCgpICsgZ2d0aXRsZSgiUHJvYmxlbSAyIikgKyB0aGVtZV9ncmF5KGJhc2Vfc2l6ZSA9IDIwKQoKcDMgPC0gZ2dwbG90KGRhdGEgPSBtb3ZpZXMsIG1hcHBpbmcgPSBhZXMoeCA9IGJ1ZGdldCwgeSA9IHJhdGluZykpICsKICBnZW9tX3BvaW50KCkgKyBnZ3RpdGxlKCJQcm9ibGVtIDMiKSArIHRoZW1lX2dyYXkoYmFzZV9zaXplID0gMjApCgpwNCA8LSBnZ3Bsb3QoZGF0YSA9IGJlY2hkZWwsIG1hcHBpbmcgPSBhZXMoeCA9IGxvZyhidWRnZXRfMjAxMywgMTApKSkgKwogIGdlb21faGlzdG9ncmFtKGNvbG9yID0gIndoaXRlIiwgYmlucyA9IDEwKSArIGdndGl0bGUoIlByb2JsZW0gNCIpICsKICB0aGVtZV9ncmF5KGJhc2Vfc2l6ZSA9IDIwKQoKZ3JpZC5hcnJhbmdlKHAxLCBwMiwgcDMsIHA0LCBuY29sID0gMiwgcGFkZGluZyA9IHVuaXQoMC41LCAibGluZSIpLAogICAgICAgICAgICAgd2lkdGhzID0gYygyLjYsIDEuNCkpCgpgYGAKCi0tLQoKY2xhc3M6IGludmVyc2UsIGNlbnRlciwgbWlkZGxlCgojIERFTU8gb2YgYGdncGxvdDJgIGluIFJTdHVkaW8KCi0tLQoKY2xhc3M6IGNlbnRlciwgbWlkZGxlCgojIyMgRGV0ZXJtaW5pbmcgdGhlIGFwcHJvcHJpYXRlIHBsb3QKCjxhIGhyZWY9Imh0dHBzOi8vY29nZ2xlLml0L2RpYWdyYW0vVl9HMmd6dWtURG9RLWFadCI+PGltZyBzcmM9ImZpZ3VyZS92aXpfbWluZG1hcC5wbmciIHN0eWxlPSJ3aWR0aDogNDAwcHg7Ii8+PGE+CgotLS0KCmNsYXNzOiBpbnZlcnNlLCBjZW50ZXIsIG1pZGRsZQpuYW1lOiB3cmFuZ2xlCgojIyBEYXkgMgoKIyMgRGF0YSBXcmFuZ2xpbmcKCi0tLQoKIyMjIGBnYXBtaW5kZXJgIGRhdGEgZnJhbWUgaW4gdGhlIGBnYXBtaW5kZXJgIHBhY2thZ2UKCmBgYHtyIHJvd3MucHJpbnQ9MTV9CmxpYnJhcnkoZ2FwbWluZGVyKQpnYXBtaW5kZXIKYGBgCgotLS0KCiMjIEJhc2UgUiB2ZXJzdXMgdGhlIGB0aWR5dmVyc2VgCgpTYXkgd2Ugd2FudGVkIG1lYW4gbGlmZSBleHBlY3RhbmN5IGFjcm9zcyBhbGwgeWVhcnMgZm9yIEFzaWEKCi0tCgpgYGB7cn0KIyBCYXNlIFIKYXNpYSA8LSBnYXBtaW5kZXJbZ2FwbWluZGVyJGNvbnRpbmVudCA9PSAiQXNpYSIsIF0KbWVhbihhc2lhJGxpZmVFeHApCmBgYAotLQogCmBgYHtyfQpsaWJyYXJ5KGRwbHlyKQpnYXBtaW5kZXIgJT4lIGZpbHRlcihjb250aW5lbnQgPT0gIkFzaWEiKSAlPiUKICBzdW1tYXJpemUobWVhbl9leHAgPSBtZWFuKGxpZmVFeHApKQpgYGAKCi0tLQoKIyMgVGhlIHBpcGUgYCU+JWAKCmByIGtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJmaWd1cmUvcGlwZS5wbmciKWAgJmVtc3A7ICZlbXNwO2ByIGtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJmaWd1cmUvTWFncml0dGVQaXBlLmpwZyIpYAotLQoKLSBBIHdheSB0byBjaGFpbiB0b2dldGhlciBjb21tYW5kcwotLQoKLSBJdCBpcyAqZXNzZW50aWFsbHkqIHRoZSBgZHBseXJgIGVxdWl2YWxlbnQgdG8gdGhlIDxicj4gYCtgIGluIGBnZ3Bsb3QyYAoKLS0tCgojIyBUaGUgNU5HIG9mIGRhdGEgdml6Ci0tCgojIyMgYGdlb21fcG9pbnQoKWA8YnI+IGBnZW9tX2xpbmUoKWAgPGJyPiBgZ2VvbV9oaXN0b2dyYW0oKWA8YnI+ICBgZ2VvbV9ib3hwbG90KClgPGJyPiBgZ2VvbV9iYXIoKWAKCi0tLQoKIyBUaGUgRml2ZSBNYWluIFZlcmJzICg1TVYpIG9mIGRhdGEgd3JhbmdsaW5nCgojIyMgYGZpbHRlcigpYCA8YnI+IGBzdW1tYXJpemUoKWAgPGJyPiBgZ3JvdXBfYnkoKWAgPGJyPiBgbXV0YXRlKClgIDxicj4gYGFycmFuZ2UoKWAKCi0tLQoKIyMgYGZpbHRlcigpYAoKLSBTZWxlY3QgYSBzdWJzZXQgb2YgdGhlIHJvd3Mgb2YgYSBkYXRhIGZyYW1lLiAKCi0gVGhlIGFyZ3VtZW50cyBhcmUgdGhlICJmaWx0ZXJzIiB0aGF0IHlvdSdkIGxpa2UgdG8gYXBwbHkuCi0tCgpgYGB7cn0KbGlicmFyeShnYXBtaW5kZXIpOyBsaWJyYXJ5KGRwbHlyKQpnYXBfMjAwNyA8LSBnYXBtaW5kZXIgJT4lIGZpbHRlcih5ZWFyID09IDIwMDcpCmhlYWQoZ2FwXzIwMDcpCmBgYAoKLSBVc2UgYD09YCB0byBjb21wYXJlIGEgdmFyaWFibGUgdG8gYSB2YWx1ZQoKLS0tCgojIyBMb2dpY2FsIG9wZXJhdG9ycwoKLSBVc2UgYHxgIHRvIGNoZWNrIGZvciBhbnkgaW4gbXVsdGlwbGUgZmlsdGVycyBiZWluZyB0cnVlOgotLQoKYGBge3IgZXZhbD1GQUxTRX0KZ2FwbWluZGVyICU+JSAKICBmaWx0ZXIoeWVhciA9PSAyMDAyIHwgY29udGluZW50ID09ICJFdXJvcGUiKQpgYGAKLS0KCmBgYHtyIGVjaG89RkFMU0V9CmdhcG1pbmRlciAlPiUgCiAgZmlsdGVyKHllYXIgPT0gMjAwMiB8IGNvbnRpbmVudCA9PSAiRXVyb3BlIikKYGBgCgotLS0KCiMjIExvZ2ljYWwgb3BlcmF0b3JzCgotIFVzZSBgJmAgb3IgYCxgIHRvIGNoZWNrIGZvciBhbGwgb2YgbXVsdGlwbGUgZmlsdGVycyBiZWluZyB0cnVlOgotLQoKYGBge3IgZXZhbD1GQUxTRX0KZ2FwbWluZGVyICU+JSAKICBmaWx0ZXIoeWVhciA9PSAyMDAyLCBjb250aW5lbnQgPT0gIkV1cm9wZSIpCmBgYAoKYGBge3IgZWNobz1GQUxTRX0KZ2FwbWluZGVyICU+JSAKICBmaWx0ZXIoeWVhciA9PSAyMDAyLCBjb250aW5lbnQgPT0gIkV1cm9wZSIpCmBgYAoKLS0tCgojIyBMb2dpY2FsIG9wZXJhdG9ycwoKLSBVc2UgYCVpbiVgIHRvIGNoZWNrIGZvciBhbnkgYmVpbmcgdHJ1ZSA8YnI+IChzaG9ydGN1dCB0byB1c2luZyBgfGAgcmVwZWF0ZWRseSB3aXRoIGA9PWApCi0tCgpgYGB7ciBldmFsPUZBTFNFfQpnYXBtaW5kZXIgJT4lIAogIGZpbHRlcihjb3VudHJ5ICVpbiUgYygiQXJnZW50aW5hIiwgIkJlbGdpdW0iLCAiTWV4aWNvIiksCiAgICAgICAgIHllYXIgJWluJSBjKDE5ODcsIDE5OTIpKQpgYGAKLS0KCmBgYHtyIGVjaG89RkFMU0V9CmdhcG1pbmRlciAlPiUgCiAgZmlsdGVyKGNvdW50cnkgJWluJSBjKCJBcmdlbnRpbmEiLCAiQmVsZ2l1bSIsICJNZXhpY28iKSwKICAgICAgICAgeWVhciAlaW4lIGMoMTk4NywgMTk5MikpCmBgYAoKCi0tLQoKIyMgYHN1bW1hcml6ZSgpYAoKLSBBbnkgbnVtZXJpY2FsIHN1bW1hcnkgdGhhdCB5b3Ugd2FudCB0byBhcHBseSB0byBhIGNvbHVtbiBvZiBhIGRhdGEgZnJhbWUgaXMgc3BlY2lmaWVkIHdpdGhpbiBgc3VtbWFyaXplKClgLgoKYGBge3IgZXZhbD1GQUxTRX0KbWF4X2V4cF8xOTk3IDwtIGdhcG1pbmRlciAlPiUgCiAgZmlsdGVyKHllYXIgPT0gMTk5NykgJT4lIAogIHN1bW1hcml6ZShtYXhfZXhwID0gbWF4KGxpZmVFeHApKQptYXhfZXhwXzE5OTcKYGBgCi0tCgpgYGB7ciBlY2hvPUZBTFNFfQptYXhfZXhwXzE5OTcgPC0gZ2FwbWluZGVyICU+JSAKICBmaWx0ZXIoeWVhciA9PSAxOTk3KSAlPiUgCiAgc3VtbWFyaXplKG1heF9leHAgPSBtYXgobGlmZUV4cCkpCm1heF9leHBfMTk5NwpgYGAKCgoKLS0tCgojIyMgQ29tYmluaW5nIGBzdW1tYXJpemUoKWAgd2l0aCBgZ3JvdXBfYnkoKWAKCldoZW4geW91J2QgbGlrZSB0byBkZXRlcm1pbmUgYSBudW1lcmljYWwgc3VtbWFyeSBmb3IgYWxsCmxldmVscyBvZiBhIGRpZmZlcmVudCBjYXRlZ29yaWNhbCB2YXJpYWJsZQoKYGBge3IgZXZhbD1GQUxTRX0KbWF4X2V4cF8xOTk3X2J5X2NvbnQgPC0gZ2FwbWluZGVyICU+JSAKICBmaWx0ZXIoeWVhciA9PSAxOTk3KSAlPiUgCiAgZ3JvdXBfYnkoY29udGluZW50KSAlPiUKICBzdW1tYXJpemUobWF4X2V4cCA9IG1heChsaWZlRXhwKSkKbWF4X2V4cF8xOTk3X2J5X2NvbnQKYGBgCgotLQpgYGB7ciBlY2hvPUZBTFNFfQptYXhfZXhwXzE5OTdfYnlfY29udCA8LSBnYXBtaW5kZXIgJT4lIAogIGZpbHRlcih5ZWFyID09IDE5OTcpICU+JSAKICBncm91cF9ieShjb250aW5lbnQpICU+JQogIHN1bW1hcml6ZShtYXhfZXhwID0gbWF4KGxpZmVFeHApKQptYXhfZXhwXzE5OTdfYnlfY29udApgYGAKCi0tLQoKIyMjIFdpdGhvdXQgdGhlIGAlPiVgCgpJdCdzIGhhcmQgdG8gYXBwcmVjaWF0ZSB0aGUgYCU+JWAgd2l0aG91dCBzZWVpbmcgd2hhdCB0aGUgY29kZSB3b3VsZCBsb29rIGxpa2Ugd2l0aG91dCBpdDoKCmBgYHtyfQptYXhfZXhwXzE5OTdfYnlfY29udCA8LSAKICBzdW1tYXJpemUoCiAgICBncm91cF9ieSgKICAgICAgZmlsdGVyKAogICAgICAgIGdhcG1pbmRlciwgCiAgICAgICAgICB5ZWFyID09IDE5OTcpLCAKICAgICAgY29udGluZW50KSwKICAgIG1heF9leHAgPSBtYXgobGlmZUV4cCkpCm1heF9leHBfMTk5N19ieV9jb250CmBgYAoKCgotLS0KCiMjIGBnZ3Bsb3QyYCByZXZpc2l0ZWQKCkZvciBhZ2dyZWdhdGVkIGRhdGEsIHVzZSBgZ2VvbV9jb2xgCgpgYGB7ciBmaWcuaGVpZ2h0PTQuNX0KZ2dwbG90KGRhdGEgPSBtYXhfZXhwXzE5OTdfYnlfY29udCwgCiAgICAgICBtYXBwaW5nID0gYWVzKHggPSBjb250aW5lbnQsIHkgPSBtYXhfZXhwKSkgKwogIGdlb21fY29sKCkKYGBgCi0tLQoKCiMjIFRoZSA1TVYKCi0gYGZpbHRlcigpYAotIGBzdW1tYXJpemUoKWAKLSBgZ3JvdXBfYnkoKWAKLS0KCi0gYG11dGF0ZSgpYAoKLS0KLSBgYXJyYW5nZSgpYAoKLS0tCgojIyBgbXV0YXRlKClgCgotIEFsbG93cyB5b3UgdG8gCiAgICAxLiA8Zm9udCBjb2xvcj0iYmx1ZSI+Y3JlYXRlIGEgbmV3IHZhcmlhYmxlIHdpdGggYSBzcGVjaWZpYyB2YWx1ZTwvZm9udD4gT1IKICAgIDIuIGNyZWF0ZSBhIG5ldyB2YXJpYWJsZSBiYXNlZCBvbiBvdGhlciB2YXJpYWJsZXMgT1IKICAgIDMuIGNoYW5nZSB0aGUgY29udGVudHMgb2YgYW4gZXhpc3RpbmcgdmFyaWFibGUKCi0tCgpgYGB7cn0KZ2FwX3BsdXMgPC0gZ2FwbWluZGVyICU+JSBtdXRhdGUoanVzdF9vbmUgPSAxKQpoZWFkKGdhcF9wbHVzKQpgYGAKCi0tLQoKIyMgYG11dGF0ZSgpYAoKLSBBbGxvd3MgeW91IHRvIAogICAgMS4gY3JlYXRlIGEgbmV3IHZhcmlhYmxlIHdpdGggYSBzcGVjaWZpYyB2YWx1ZSBPUgogICAgMi4gPGZvbnQgY29sb3I9ImJsdWUiPmNyZWF0ZSBhIG5ldyB2YXJpYWJsZSBiYXNlZCBvbiBvdGhlciB2YXJpYWJsZXM8L2ZvbnQ+IE9SCiAgICAzLiBjaGFuZ2UgdGhlIGNvbnRlbnRzIG9mIGFuIGV4aXN0aW5nIHZhcmlhYmxlCgotLQoKYGBge3J9CmdhcF93X2dkcCA8LSBnYXBtaW5kZXIgJT4lIG11dGF0ZShnZHAgPSBwb3AgKiBnZHBQZXJjYXApCmhlYWQoZ2FwX3dfZ2RwKQpgYGAKCi0tLQoKIyMgYG11dGF0ZSgpYAoKLSBBbGxvd3MgeW91IHRvIAogICAgMS4gY3JlYXRlIGEgbmV3IHZhcmlhYmxlIHdpdGggYSBzcGVjaWZpYyB2YWx1ZSBPUgogICAgMi4gY3JlYXRlIGEgbmV3IHZhcmlhYmxlIGJhc2VkIG9uIG90aGVyIHZhcmlhYmxlcyBPUgogICAgMy4gPGZvbnQgY29sb3I9ImJsdWUiPmNoYW5nZSB0aGUgY29udGVudHMgb2YgYW4gZXhpc3RpbmcgdmFyaWFibGU8L2ZvbnQ+CgotLQoKYGBge3J9CmdhcF93ZWlyZCA8LSBnYXBtaW5kZXIgJT4lIG11dGF0ZShwb3AgPSBwb3AgKyAxMDAwKQpoZWFkKGdhcF93ZWlyZCkKYGBgCgotLS0KCiMjIGBhcnJhbmdlKClgCgotIFJlb3JkZXJzIHRoZSByb3dzIGluIGEgZGF0YSBmcmFtZSBiYXNlZCBvbiB0aGUgdmFsdWVzIG9mIG9uZSBvciBtb3JlIHZhcmlhYmxlcwotLQoKYGBge3J9CmdhcG1pbmRlciAlPiUKICBhcnJhbmdlKHllYXIsIGNvdW50cnkpCmBgYAoKLS0tCgojIyBgYXJyYW5nZSgpYAoKLSBDYW4gYWxzbyBwdXQgaW50byBkZXNjZW5kaW5nIG9yZGVyCi0tCgpgYGB7ciBkZXNjfQpnYXBtaW5kZXIgJT4lCiAgZmlsdGVyKHllYXIgPiAyMDAwKSAlPiUKICBhcnJhbmdlKGRlc2MobGlmZUV4cCkpCmBgYAoKLS0tCgojIyBEb24ndCBtaXggdXAgYGFycmFuZ2VgIGFuZCBgZ3JvdXBfYnlgCgotIGBncm91cF9ieWAgaXMgdXNlZCAobW9zdGx5KSB3aXRoIGBzdW1tYXJpemVgIHRvIGNhbGN1bGF0ZSBzdW1tYXJpZXMgb3ZlciBncm91cHMKCi0gYGFycmFuZ2VgIGlzIHVzZWQgZm9yIHNvcnRpbmcKCi0tLQoKIyMgRG9uJ3QgbWl4IHVwIGBhcnJhbmdlYCBhbmQgYGdyb3VwX2J5YAoKVGhpcyBkb2Vzbid0IHJlYWxseSBkbyBhbnl0aGluZyB1c2VmdWwKCmBgYHtyIHJvd3MucHJpbnQ9MTB9CmdhcG1pbmRlciAlPiUgZ3JvdXBfYnkoeWVhcikKYGBgCgotLS0KCiMjIERvbid0IG1peCB1cCBgYXJyYW5nZWAgYW5kIGBncm91cF9ieWAKCkJ1dCB0aGlzIGRvZXMKCmBgYHtyIHJvd3MucHJpbnQ9MTB9CmdhcG1pbmRlciAlPiUgYXJyYW5nZSh5ZWFyKQpgYGAKCi0tLQoKIyMgQ2hhbmdpbmcgb2Ygb2JzZXJ2YXRpb24gdW5pdAoKVHJ1ZSBvciBGYWxzZQo+IEVhY2ggb2YgYGZpbHRlcmAsIGBtdXRhdGVgLCBhbmQgYGFycmFuZ2VgIGNoYW5nZSB0aGUgb2JzZXJ2YXRpb25hbCB1bml0LgoKLS0KClRydWUgb3IgRmFsc2UKPiBgZ3JvdXBfYnkoKSAlPiUgc3VtbWFyaXplKClgIGNoYW5nZXMgdGhlIG9ic2VydmF0aW9uYWwgdW5pdC4KCjwhLS0gCkRyYXcgZGlhZ3JhbSBmb3IgYXZlcmFnZSBtb250aGx5IHRlbXAgYWdncmVnYXRlZCBsaWtlIG9uIHJzdHVkaW86OmNvbmYgc2xpZGVzCi0tPgoKLS0tCgojIyBXaGF0IGlzIG1lYW50IGJ5ICJqb2luaW5nIGRhdGEgZnJhbWVzIiBhbmQgPGJyPiB3aHkgaXMgaXQgdXNlZnVsPwoKLS0KCmBgYHtyIGVjaG89RkFMU0UsIGZpZy5hbGlnbj0nY2VudGVyJ30Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImh0dHBzOi8vaXNtYXljLmdpdGh1Yi5pby9tb2Rlcm5kaXZlci1ib29rL2ltYWdlcy9qb2luLWlubmVyLnBuZyIpCmBgYAoKLS0tCgojIyMgRG9lcyBjb3N0IG9mIGxpdmluZyBpbiBhIHN0YXRlIHJlbGF0ZSB0byB3aGV0aGVyIHBvbGljZSBvZmZpY2VycyBsaXZlIGluIHRoZSBjaXRpZXMgdGhleSBwYXRyb2w/ICBXaGF0IGFib3V0IHN0YXRlIHBvbGl0aWNhbCBpZGVvbG9neT8KCgpgYGB7ciBldmFsPUZBTFNFfQpsaWJyYXJ5KGZpdmV0aGlydHllaWdodCk7IGxpYnJhcnkocmVhZHIpOyBsaWJyYXJ5KGRwbHlyKQpwb2xpY2UyIDwtIHBvbGljZV9sb2NhbHMgJT4lIHNlbGVjdChjaXR5LCBhbGwpCmlkZW9sb2d5IDwtIHJlYWRfY3N2KCJodHRwczovL2lzbWF5Yy5naXRodWIuaW8vRWZmZWN0aXZlLURhdGEtU3Rvcnl0ZWxsaW5nLXVzaW5nLXRoZS10aWR5dmVyc2UvZGF0YXNldHMvaWRlb2xvZ3kuY3N2IikKcG9saWNlX2pvaW4gPC0gaW5uZXJfam9pbih4ID0gcG9saWNlMiwgeSA9IGlkZW9sb2d5LCBieSA9ICJjaXR5IikKcG9saWNlX2pvaW4KYGBgCgotLQoKYGBge3IgZWNobz1GQUxTRX0KbGlicmFyeShmaXZldGhpcnR5ZWlnaHQpOyBsaWJyYXJ5KHJlYWRyKTsgbGlicmFyeShkcGx5cikKcG9saWNlMiA8LSBwb2xpY2VfbG9jYWxzICU+JSBzZWxlY3QoY2l0eSwgYWxsKQppZGVvbG9neSA8LSByZWFkX2NzdigiaHR0cHM6Ly9pc21heWMuZ2l0aHViLmlvL0VmZmVjdGl2ZS1EYXRhLVN0b3J5dGVsbGluZy11c2luZy10aGUtdGlkeXZlcnNlL2RhdGFzZXRzL2lkZW9sb2d5LmNzdiIpCnBvbGljZV9qb2luIDwtIGlubmVyX2pvaW4oeCA9IHBvbGljZTIsIHkgPSBpZGVvbG9neSwgYnkgPSAiY2l0eSIpCnBvbGljZV9qb2luCmBgYAoKCi0tLQoKYGBge3J9CnVybCA8LSBwYXN0ZTAoImh0dHBzOi8vaXNtYXljLmdpdGh1Yi5pby8iLAogICAgICAgICAgICAgICJFZmZlY3RpdmUtRGF0YS1TdG9yeXRlbGxpbmctdXNpbmctdGhlLXRpZHl2ZXJzZS8iLAogICAgICAgICAgICAgICJkYXRhc2V0cy9jb3N0X29mX2xpdmluZy5jc3YiKQpjb3N0X29mX2xpdmluZyA8LSByZWFkX2Nzdih1cmwpCnBvbGljZV9qb2luX2Nvc3QgPC0gaW5uZXJfam9pbigKICAgIHggPSBwb2xpY2Vfam9pbiwgCiAgICB5ID0gY29zdF9vZl9saXZpbmcsIAogICAgYnkgPSAic3RhdGUiCiAgKQpwb2xpY2Vfam9pbl9jb3N0ICU+JSBzZWxlY3QoLXN0YXRlKSAlPiUgYXJyYW5nZShjaXR5KQpgYGAKCi0tLQoKIyMjIERvZXMgY29zdCBvZiBsaXZpbmcgaW4gYSBzdGF0ZSByZWxhdGUgdG8gd2hldGhlciBwb2xpY2Ugb2ZmaWNlcnMgbGl2ZSBpbiB0aGUgY2l0aWVzIHRoZXkgcGF0cm9sPyAgV2hhdCBhYm91dCBzdGF0ZSBwb2xpdGljYWwgaWRlb2xvZ3k/CgpgYGB7ciBmaWcud2lkdGg9MTB9CmdncGxvdChkYXRhID0gcG9saWNlX2pvaW5fY29zdCwKICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IGluZGV4LCB5ID0gYWxsKSkgKwogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyhjb2xvciA9IHN0YXRlX2lkZW9sb2d5KSkgKwogIGxhYnMoeCA9ICJDb3N0IG9mIExpdmluZyBJbmRleCIsIHkgPSAiJSBPZmZpY2VycyBMaXZpbmcgaW4gQ2l0eSIpCmBgYAoKLS0tCgojIyBQcmFjdGljZSA8c21hbGw+PHNtYWxsPihMYXkgb3V0IHdoYXQgdGhlIHJlc3VsdGluZyB0YWJsZSBzaG91bGQgbG9vayBsaWtlIG9uIHBhcGVyIGZpcnN0Lik8L3NtYWxsPjwvc21hbGw+CgpVc2UgdGhlIDVNViB0byBhbnN3ZXIgcHJvYmxlbXMgZnJvbSBSIGRhdGEgcGFja2FnZXMsIGUuZy4sIFtgbnljZmxpZ2h0czEzYCAkXHJpZ2h0YXJyb3ckIGB3ZWF0aGVyYF0gCgoxLiBXaGF0IGlzIHRoZSBtYXhpbXVtIGFycml2YWwgZGVsYXkgZm9yIGVhY2ggY2FycmllciBkZXBhcnRpbmcgSkZLPyBbYG55Y2ZsaWdodHMxM2AgJFxyaWdodGFycm93JCBgZmxpZ2h0c2BdCgoyLiBEZXRlcm1pbmUgdGhlIHRvcCBmaXZlIG1vdmllcyBpbiB0ZXJtcyBvZiBkb21lc3RpYyByZXR1cm4gb24gaW52ZXN0bWVudCBmb3IgMjAxMyBzY2FsZWQgZGF0YTxicj4gW2BmaXZldGhpcnR5ZWlnaHRgICRccmlnaHRhcnJvdyQgYGJlY2hkZWxgXQoKMy4gW0luY2x1ZGUgdGhlIG5hbWUgb2YgdGhlIGRlc3RpbmF0aW9uIGFpcnBvcnQgYXMgYSBjb2x1bW4gaW4gdGhlIGBmbGlnaHRzYCBkYXRhIGZyYW1lXShodHRwOi8vcjRkcy5oYWQuY28ubnovZGlhZ3JhbXMvcmVsYXRpb25hbC1ueWNmbGlnaHRzLnBuZykgPGJyPiBbYG55Y2ZsaWdodHMxM2AgJFxyaWdodGFycm93JCBgZmxpZ2h0c2AsIGBhaXJwb3J0c2BdCgotLS0KCgpjbGFzczogaW52ZXJzZSwgY2VudGVyLCBtaWRkbGUKCiMgREVNTyBvZiBgZHBseXJgIGluIFJTdHVkaW8KCi0tLQoKPCEtLQojIyBIb21ld29yayBmb3IgdG9tb3Jyb3cKCi0gUmV2aWV3IHRoZSBEYXRhIEltcG9ydCBjaGVhdHNoZWV0IGFuZCB1c2UgdGhlIGByZWFkcmAsIGByZWFkeGxgLCBhbmQgYGhhdmVuYCBwYWNrYWdlcyB0byByZWFkIGluIGRhdGEgZnJvbSBDU1ZzLCBFeGNlbCBYTFMvWExTWCBmaWxlcywgU1RBVEEvU1BTUyBmaWxlcwoKLSBVc2UgYGdncGxvdDJgIGFuZCBgZHBseXJgIHRvIG1ha2UgZ3JhcGhpY3MgYW5kIHByb2R1Y2UgZGF0YSB3cmFuZ2xpbmcgb24gZGF0YSBzZXRzIG9mIGludGVyZXN0IHRvIHlvdSByZWFkIGluIGZyb20gdGhlIHByZXZpb3VzIHN0ZXAKLS0+CgpjbGFzczogaW52ZXJzZSwgY2VudGVyLCBtaWRkbGUKCgojIERhdGEgSW1wb3J0aW5nIGFuZCBUaWR5aW5nCgotLS0KCiMjIGB0aWR5dmVyc2VgIHBhY2thZ2VzCgoqKklNUE9SVCoqCgotIGBoYXZlbmAgZm9yIFNQU1MsIFNBUywgYW5kIFN0YXRhIGRhdGEgZmlsZXMKLSBganNvbmxpdGVgIGZvciBKU09OIGZpbGVzCi0gYHJlYWR4bGAgZm9yIFhMUyBhbmQgWExTWCBmaWxlcwotIGByZWFkcmAgZm9yIENTViBhbmQgVFNWIGZpbGVzIChhbmQgUiBzcGVjaWZpYyBSRFMgZmlsZXMpCgo8YnI+CgoqKlRJRFlJTkcqKgoKLSBgdGlkeXJgIGZvciBjb252ZXJ0aW5nICJtZXNzeSIgaW50byAidGlkeSIgZGF0YSBmcmFtZXMKCi0tLQoKbmFtZTogaW1wb3J0CgojIyBCYXNpY3Mgb2YgSW1wb3J0aW5nCgo8c21hbGw+V2Ugd2lsbCBiZWdpbiBieSBkb3dubG9hZGluZyBhbmQgaW1wb3J0aW5nIGEgdmFyaWV0eSBvZiBkaWZmZXJlbnQgIm1lc3N5IiBkYXRhIHNldHMuICBZb3UgY2FuIGRvd25sb2FkIGFsbCBvZiB0aGVtIGluIGEgWklQIGZpbGUgYXQgPGh0dHA6Ly9iaXQubHkvcmVlZC1tZXNzeS1kYXRhPi4gIFRoZSBsaW5rcyBiZWxvdyBnbyB0byB0aGUgb3JpZ2luYWwgc291cmNlcy4gIEkndmUgY29udmVydGVkIHRoZXNlIG9yaWdpbmFsIHNvdXJjZXMgaW50byBkaWZmZXJlbnQgZm9ybWF0cy48L3NtYWxsPgoKCi0gW0xpZmUgRXhwZWN0YW5jeSBieSB5ZWFyIGZvciBjb3VudHJpZXMgc2luY2UgMTk1MSAoQ1NWKV0oaHR0cHM6Ly9zcHJlYWRzaGVldHMuZ29vZ2xlLmNvbS9wdWI/a2V5PXBoQXdjTkFWdXlqMnRQTHhLdnZuTlBBJm91dHB1dD14bHMpCgotIFtXb3JsZCBIZWFsdGggT3JnYW5pemF0aW9uIFRCIGRhdGEgKFN0YXRhIERUQSldKGh0dHA6Ly93d3cud2hvLmludC90Yi9jb3VudHJ5L2RhdGEvZG93bmxvYWQvZW4vKQoKLSBbQW5udWFsIEVzdGltYXRlcyBvZiBQb3B1bGF0aW9uIGJ5IEFnZSwgU2V4LCBSYWNlLCBhbmQgSGlzcGFuaWMgT3JpZ2luIGZvciBPcmVnb24gQ291bnRpZXMgKFhMU1gpXShodHRwczovL3d3dy5jZW5zdXMuZ292L3BvcGVzdC9kYXRhL2NvdW50aWVzL2FzcmgvMjAxMS9DQy1FU1QyMDExLWFsbGRhdGEuaHRtbCkKLSBbRWR1Y2F0aW9uYWwgYXR0YWlubWVudCBmb3IgdGhlIFUuUy4sIFN0YXRlcywgYW5kIGNvdW50aWVzLCAxOTcwLTIwMTQgKEpTT04pXShodHRwOi8vd3d3LmVycy51c2RhLmdvdi9kYXRhLXByb2R1Y3RzL2NvdW50eS1sZXZlbC1kYXRhLXNldHMvZG93bmxvYWQtZGF0YS5hc3B4KQotIFtDb3VudHkgbGV2ZWwgcmVzdWx0cyBmb3IgMjAxMiBQT1RVUyBlbGVjdGlvbiBmcm9tIFRoZSBHdWFyZGlhbiAoU1BTUyBTQVYpXShodHRwczovL2Z1c2lvbnRhYmxlcy5nb29nbGUuY29tL0RhdGFTb3VyY2U/ZG9jaWQ9MXFjUUxxckFJQWUzUmNFZmRXU21fUWNYTUxtdGVWZzR1U3BTczFyTSkKCgotLS0KCmNsYXNzOiBjZW50ZXIsIG1pZGRsZSwgaW52ZXJzZQoKIyMgRGVtb25zdHJhdGlvbiBpbiBSU3R1ZGlvCgotLS0KCiMjIFByYWN0aWNlCgotIERvd25sb2FkIHRoZSBmb3VyIG90aGVyIGZpbGVzIGFuZCBpbXBvcnQgdGhlbSBpbnRvIFIgdXNpbmcgdGhlIGFwcHJvcHJpYXRlIHBhY2thZ2UKICAgIC0gWW91IG1heSBuZWVkIHRvIGNoZWNrIG91dCB0aGUgaGVscCBwYWdlcyBmb3IgdGhlIGRpZmZlcmVudCBwYWNrYWdlcwogICAgICAgIC0gW2BoYXZlbmAgZm9yIFNQU1MsIFNBUywgYW5kIFN0YXRhIGRhdGEgZmlsZXNdKGh0dHA6Ly9oYXZlbi50aWR5dmVyc2Uub3JnLykKICAgICAgICAtIFtganNvbmxpdGVgIGZvciBKU09OIGZpbGVzXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvanNvbmxpdGUvdmlnbmV0dGVzL2pzb24tYWFxdWlja3N0YXJ0Lmh0bWwpCiAgICAgICAgLSBbYHJlYWR4bGAgZm9yIFhMUyBhbmQgWExTWCBmaWxlc10oaHR0cHM6Ly9naXRodWIuY29tL2hhZGxleS9yZWFkeGwpCiAgICAgICAgLSBbYHJlYWRyYCBmb3IgQ1NWL1RTViBmaWxlcyAoJiBSIHNwZWNpZmljIFJEUyBmaWxlcyldKGh0dHA6Ly9yZWFkci50aWR5dmVyc2Uub3JnLykKICAgIC0gR2l2ZSB0aGVtIHRoZSBmb2xsb3dpbmcgbmFtZXM6IGB3aG9fZGZgLCBgY291bnR5X3BvcF9kZmAsIGBlZHVfY291bnR5X2RmYCwgYW5kIGBwb3R1czEyX2RmYAogIAotLS0KCm5hbWU6IHRpZHkKY2xhc3M6IGludmVyc2UsIG1pZGRsZSwgY2VudGVyCgojIFRpZHkgRGF0YQoKCi0tLQoKPGltZyBzcmM9Imh0dHA6Ly9nYXJyZXR0Z21hbi5naXRodWIuaW8vaW1hZ2VzL3RpZHktMS5wbmciIHN0eWxlPSJ3aWR0aDogNzUwcHg7Ii8+CgoxLiBFYWNoIHZhcmlhYmxlIGZvcm1zIGEgY29sdW1uLgoyLiBFYWNoIG9ic2VydmF0aW9uIGZvcm1zIGEgcm93LgozLiBFYWNoIHR5cGUgb2Ygb2JzZXJ2YXRpb25hbCB1bml0IGZvcm1zIGEgdGFibGUuCgpUaGUgdGhpcmQgcG9pbnQgbWVhbnMgd2UgZG9uJ3QgbWl4IGFwcGxlcyBhbmQgb3Jhbmdlcy4KCi0tLQoKIyMgV2hhdCBpcyBUaWR5IERhdGE/CgoxLiBFYWNoIG9ic2VydmF0aW9uIGZvcm1zIGEgcm93LiBJbiBvdGhlciB3b3JkcywgZWFjaCByb3cgY29ycmVzcG9uZHMgdG8gYSBzaW5nbGUgaW5zdGFuY2Ugb2YgYW4gPHU+b2JzZXJ2YXRpb25hbCB1bml0PC91PgoxLiBFYWNoIHZhcmlhYmxlIGZvcm1zIGEgY29sdW1uOgogICAgKyBTb21lIHZhcmlhYmxlcyBtYXkgYmUgdXNlZCB0byBpZGVudGlmeSB0aGUgPHU+b2JzZXJ2YXRpb25hbCB1bml0czwvdT4uIAogICAgKyBGb3Igb3JnYW5pemF0aW9uYWwgcHVycG9zZXMsIGl0J3MgZ2VuZXJhbGx5IGJldHRlciB0byBwdXQgdGhlc2UgaW4gdGhlIGxlZnQtaGFuZCBjb2x1bW5zCjEuIEVhY2ggdHlwZSBvZiBvYnNlcnZhdGlvbmFsIHVuaXQgZm9ybXMgYSB0YWJsZSB3aXRoIHRoZSBlbnRyaWVzIGluIHRoZSB0YWJsZSBjb3JyZXNwb25kaW5nIHRvIHZhbHVlcy4KCi0tLQoKIyMgRGlmZmVyZW50aWF0aW5nIGJldHdlZW4gPHU+bmVhdDwvdT4gZGF0YSBhbmQgPHU+dGlkeTwvdT4gZGF0YQoKLSBDb2xsb3F1aWFsbHksIHRoZXkgbWVhbiB0aGUgc2FtZSB0aGluZwotIEJ1dCBpbiBvdXIgY29udGV4dCwgb25lIGlzIGEgc3Vic2V0IG9mIHRoZSBvdGhlci4gCgo8YnI+Cgo8dT5OZWF0PC91PiBkYXRhIGlzIAogIC0gZWFzeSB0byBsb29rIGF0LCAKICAtIG9yZ2FuaXplZCBuaWNlbHksIGFuZCAKICAtIGluIHRhYmxlIGZvcm0uCgotLQoKPHU+VGlkeTwvdT4gZGF0YSBpcyBuZWF0IGJ1dCBhbHNvIGFiaWRlcyBieSBhIHNldCBvZiB0aHJlZSBydWxlcy4KCi0tLQoKY2xhc3M6IGNlbnRlciwgbWlkZGxlCgo8YSBocmVmPSJodHRwOi8vc3RyZWFtMS5naWZzb3VwLmNvbS92aWV3OC8yMDE1MDQwNC81MTkyODU5L2xlYm93c2tpLWFiaWRlcy1vLmdpZiI+PGltZyBzcmM9ImZpZ3VyZS9sZWJvd3NraS1hYmlkZXMtby5naWYiIHN0eWxlPSJ3aWR0aDogNDUwcHg7Ii8+PC9hPgoKCjxpbWcgc3JjPSJmaWd1cmUvdGlkeS0xLnBuZyIgYWx0PSJEcmF3aW5nIiBzdHlsZT0id2lkdGg6IDc1MHB4OyIvPgoKLS0tCgojIyBJcyB0aGlzIHRpZHk/CgpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KGZpdmV0aGlydHllaWdodCkKc2V0LnNlZWQoMikKYmVjaGRlbCAlPiUgc2FtcGxlX24oMTIpICU+JQogIHNlbGVjdCh5ZWFyLCB0aXRsZSwgY2xlYW5fdGVzdCwgYnVkZ2V0XzIwMTMpICU+JQogIGFycmFuZ2UodGl0bGUpICU+JQogIGthYmxlKGZvcm1hdCA9ICJodG1sIikKYGBgCgoKLS0tCgpuYW1lOiBkZW1zY29yZQoKIyMgSG93IGFib3V0IHRoaXM/IElzIHRoaXMgdGlkeT8KCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmRlbV9zY29yZSA8LSByZWFkX2NzdigiZGF0YS9kZW1fc2NvcmUuY3N2IikKa25pdHI6OmthYmxlKGRlbV9zY29yZSAlPiUgc2xpY2UoMToxMiksIGZvcm1hdCA9ICJodG1sIikKYGBgCgotLS0KCm5hbWU6IHdoeXRpZHkKCiMjIFdoeSBpcyB0aWR5IGRhdGEgaW1wb3J0YW50PwoKLSBUaGluayBhYm91dCB0cnlpbmcgdG8gcGxvdCBkZW1vY3JhY3kgc2NvcmUgYWNyb3NzIHllYXJzIGluIHRoZSBzaW1wbGVzdCB3YXkgcG9zc2libGUuCi0tCgotIEl0IHdvdWxkIGJlIG11Y2ggZWFzaWVyIGlmIHRoZSBkYXRhIGxvb2tlZCBsaWtlIHdoYXQgZm9sbG93cyBpbnN0ZWFkIHNvIHdlIGNvdWxkIHB1dCAKICAgIC0gYHllYXJgIG9uIHRoZSBgeGAtYXhpcyBhbmQgCiAgICAtIGBkZW1fc2NvcmVgIG9uIHRoZSBgeWAtYXhpcy4KCi0tLQoKIyMgVGlkeSBpcyBnb29kCgpgYGB7ciBlY2hvPUZBTFNFfQpkZW1fc2NvcmVfdGlkeSA8LSBkZW1fc2NvcmUgJT4lIAogIGdhdGhlcigtY291bnRyeSwga2V5ID0gInllYXIiLCB2YWx1ZSA9ICJkZW1fc2NvcmUiKSAlPiUgCiAgbXV0YXRlKHllYXIgPSBhcy5udW1lcmljKHllYXIpKSAKc2V0LnNlZWQoMikKZGVtX3Njb3JlX3RpZHkgJT4lIHNhbXBsZV9uKDEzKSAlPiUgYXJyYW5nZShjb3VudHJ5KSAlPiUgCiAga25pdHI6OmthYmxlKGZvcm1hdCA9ICJodG1sIikKYGBgCgotLS0KCiMjIExldCdzIHBsb3QgaXQKCi0gUGxvdCB0aGUgbGluZSBncmFwaCBmb3IgdGhyZWUgY291bnRyaWVzIHVzaW5nIGBnZ3Bsb3RgCgpgYGB7cn0KZGVtX3Njb3JlNCA8LSBkZW1fc2NvcmVfdGlkeSAlPiUKICBmaWx0ZXIoY291bnRyeSAlaW4lIGMoIlBha2lzdGFuIiwgIlBvcnR1Z2FsIiwgIlVydWd1YXkiKSkKZ2dwbG90KGRhdGEgPSBkZW1fc2NvcmU0LCBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLCB5ID0gZGVtX3Njb3JlKSkgKwogIGdlb21fbGluZShtYXBwaW5nID0gYWVzKGNvbG9yID0gY291bnRyeSkpCmBgYAoKLS0tCgojIyBUaWR5aW5nCgojIyMgVGhlIExpZmUgRXhwZWN0YW5jeSBieSB5ZWFyIGRhdGEKCmBgYHtyfQpsaWJyYXJ5KHJlYWRyKQpsaWZlX2V4cF9kZiA8LSByZWFkX2NzdigiZGF0YS9sZV9tZXNzLmNzdiIpCiNWaWV3KGxpZmVfZXhwX2RmKQpgYGAKCmBgYHtyIGVjaG89RkFMU0V9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJmaWd1cmUvbGVfbWVzcy5wbmciKQpgYGAKCi0tLQoKIyMgRG9pbmcgdGhlICJ0aWR5aW5nIi9yZXNoYXBpbmcKCmBgYHtyIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoZHBseXIpCihsaWZlX2V4cF90aWR5IDwtIGxpZmVfZXhwX2RmICU+JSAKICAgIGdhdGhlcihrZXkgPSAieWVhciIsIHZhbHVlID0gImxpZmVfZXhwIiwgLWNvdW50cnkpKQpgYGAKCi0tLQoKIyMgVGlkeWluZwoKIyMjIyBXb3JsZCBIZWFsdGggT3JnYW5pemF0aW9uIFRCIGRhdGEgKFN0YXRhIERUQSkKCgpgYGB7cn0KbGlicmFyeShoYXZlbikKd2hvX2RmIDwtIHJlYWRfZHRhKCJkYXRhL3doby5kdGEiKQojVmlldyh3aG9fZGYpCmBgYAoKYGBge3IgZWNobz1GQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImZpZ3VyZS93aG9fbWVzcy5wbmciKQpgYGAKCi0tLQoKIyMgV0hPIHVnbHkuLi4KCi0gVGhpcyBkYXRhIHNldCBjb250YWlucyBzdHJhbmdlIHZhcmlhYmxlIG5hbWVzIHRoYXQgd2lsbCByZXF1aXJlIHVzIHRvIGxvb2sgdXAgdGhlaXIgbWVhbmluZyBpbiB0aGUgY29ycmVzcG9uZGluZyBbKipkYXRhIGRpY3Rpb25hcnkqKl0oaHR0cHM6Ly9leHRyYW5ldC53aG8uaW50L3RtZS9nZW5lcmF0ZUNTVi5hc3A/ZHM9ZGljdGlvbmFyeSkuCgotLQoKLSBXaGF0IGRvIHdlIGtub3c/CiAgICAgLSBgY291bnRyeWAsIGBpc28yYCwgYW5kIGBpc28zYCBhcmUgcmVkdW5kYW50IGFuZCBpZGVudGlmeSB0aGUgY291bnRyeQogICAgIC0gYHllYXJgIGlzIGEgdmFyaWFibGUgYW5kIGl0IGxvb2tzIGxpa2UgaXQgY29ycmVzcG9uZHMgdG8gZWFjaCBjb3VudHJ5Ci0gQnV0IHdoYXQgaW4gdGhlIHdvcmxkIGlzIGBuZXdfc3BfbTAxNGA/IEFuZCB0aGUgb3RoZXIgY29sdW1ucz8uLi4KCi0tLQoKIyMgRmlyc3Qgc3RlcAoKTGlrZSBiZWZvcmUsIHdlIGNhbiBgZ2F0aGVyYCB0aGVzZSBub24tYGNvdW50cnlgIGFuZCBub24tYHllYXJgIHZhcmlhYmxlcyB0b2dldGhlcjoKCmBgYHtyfQp3aG9fdGlkeSA8LSB3aG9fZGYgJT4lIAogIGdhdGhlcihuZXdfc3BfbTAxNDpuZXdyZWxfZjY1LCBrZXkgPSAia2V5IiwgdmFsdWUgPSAidmFsdWUiKQpgYGAKCldlIGNhbiBub3cgc2VlIHdoYXQgdGhpcyBoYXMgZG9uZSB0byB0aGUgZGF0YSBmcmFtZToKCmBgYHtyIGV2YWw9RkFMU0V9ClZpZXcod2hvX3RpZHkpCmBgYAoKLS0tCgojIyBEYXRhIGRpY3Rpb25hcnkgc2F2ZXMgdXMgc29tZS4uLgoKMS4gVGhlIGZpcnN0IHRocmVlIGxldHRlcnMgb2YgZW50cmllcyBpbiB0aGUgYGtleWAgY29sdW1uIGNvcnJlc3BvbmQgdG8gYG5ld2Agb3IgYG9sZGAgY2FzZXMgb2YgVEIuCjIuIFRoZSBuZXh0IHR3byBsZXR0ZXJzIChhZnRlciB0aGUgYF9gKSBjb3JyZXNwb25kIHRvIFRCIHR5cGU6CiAgICAtIGByZWxgIGZvciByZWxhcHNlLCBgZXBgIGZvciBleHRyYXB1bG1vbmFyeSBUQgogICAgLSBgc25gIGZvciBzbWVhciBuZWdhdGl2ZSwgYHNwYCBmb3Igc21lYXIgcG9zaXRpdmUKMy4gVGhlIG5leHQgbGV0dGVyIGFmdGVyIHRoZSBzZWNvbmQgYF9gIGNvcnJlc3BvbmRzIHRvIHRoZSBzZXggb2YgdGhlIFRCIHBhdGllbnQuCjQuIFRoZSByZW1haW5pbmcgbnVtYmVycyBjb3JyZXNwb25kIHRvIGFnZSBncm91cDoKICAgIC0gYDAxNGAgZm9yIDAgdG8gMTQgeWVhcnMKICAgIC0gLi4uCiAgICAtIGA2NWAgZm9yIDY1IG9yIG9sZGVyCgotLS0KCi0gTG9va2luZyBvdmVyIHRoZSBlbnRyaWVzIG9mIGBrZXlgIGluIGB3aG9fdGlkeWAsIGRvIHlvdSBzZWUgYW55dGhpbmcgZWxzZSB0aGF0IGRvZXNuJ3QgbWF0Y2ggdGhlIHBhdHRlcm4/CgotIEl0IG1heSBiZSBlYXNpZXIgdG8gcmVtZW1iZXIgdGhhdCB0aGUgZW50cmllcyBvZiBga2V5YCBjb3JyZXNwb25kIHRvIGNvbHVtbiBuYW1lcyBpbiBgd2hvX2RmYDoKCmBgYHtyfQpuYW1lcyh3aG9fZGYpCmBgYAoKLS0tCgojIyBBIGZpeCB1c2luZyBgc3RyaW5ncmAKCllvdSBjYW4gcmVwbGFjZSBhbGwgb2YgdGhlIGVudHJpZXMgaW4gYGtleWAgdGhhdCBjb250YWluZWQgYG5ld3JlbGAgd2l0aCBgbmV3X3JlbGAgdmlhCgpgYGB7cn0KbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KGRwbHlyKQp3aG9fdGlkeSA8LSB3aG9fdGlkeSAlPiUgCiAgbXV0YXRlKGtleSA9IHN0cl9yZXBsYWNlKAogICAgICBzdHJpbmcgPSBrZXksIAogICAgICBwYXR0ZXJuID0gIm5ld3JlbCIsIAogICAgICByZXBsYWNlbWVudCA9ICJuZXdfcmVsIikKICAgICkKYGBgCgotLS0KCiMjIFB1bGxpbmcgYXBhcnQgdmFyaWFibGVzCgpUaGUgZW50cnkgYG5ld19zcF9tMDE0YCBpcyBhY3R1YWxseSBmb3VyIGRpZmZlcmVudCB2YXJpYWJsZXMuICBVc2UgdGhlIGBzZXBhcmF0ZWAgZnVuY3Rpb24gdG8gcHVsbCB0aGVtIGFwYXJ0OgoKYGBge3J9Cndob190aWR5IDwtIHdob190aWR5ICU+JSAKICBzZXBhcmF0ZShjb2wgPSBrZXksIGludG8gPSBjKCJuZXciLCAidHlwZSIsICJzZXhhZ2UiKSwgc2VwID0gIl8iKQp3aG9fdGlkeQpgYGAKCi0tLQoKIyMgT25lIG1vcmUgcHVsbCBhcGFydAoKLSBXZSBuZWVkIHRvIHB1bGwgYHNleGFnZWAgaW50byB0d28gZGlmZmVyZW50IHZhcmlhYmxlcy4gIAotIElmIHlvdSB1c2UgYD9zZXBhcmF0ZWAsIHlvdSdsbCBzZWUgdGhhdCB0aGUgZm9sbG93aW5nIGlzIGFuIG9wdGlvbjoKCmBgYHtyfQood2hvX3RpZHkgPC0gd2hvX3RpZHkgJT4lIAogIHNlcGFyYXRlKGNvbCA9IHNleGFnZSwgaW50byA9IGMoInNleCIsICJhZ2UiKSwgc2VwID0gMSkpCmBgYAoKLS0tCgojIyBGaW5hbCBjbGVhbmluZwoKLSBgaXNvMmAgYW5kIGBpc28zYCBhcmUgcmVkdW5kYW50IGlmIHdlIGhhdmUgYGNvdW50cnlgCi0gYG5ld2AgaXMgY29uc3RhbnQgc2luY2UgdGhpcyBvbmx5IGhhcyBuZXcgY2FzZXMgb2YgVEIKLSBMZXQncyBqdXN0IGlnbm9yZSBtaXNzaW5nIHZhbHVlcyBoZXJlCi0gV2UgYWxzbyBrbm93IHRoYXQgYHZhbHVlYCBpcyBhY3R1YWxseSBgY2FzZXNgIHNvIHdlIGNhbiBgcmVuYW1lYCB0aGF0IGNvbHVtbi4KCmBgYHtyLCB0aWR5PUZBTFNFfQp3aG9fdGlkeSA8LSB3aG9fdGlkeSAlPiUgc2VsZWN0KC1pc28yLCAtaXNvMywgLW5ldykgJT4lIAogIG5hLm9taXQoKSAlPiUgcmVuYW1lKCJjYXNlcyIgPSB2YWx1ZSkKaGVhZCh3aG9fdGlkeSwgNSkKYGBgCgotLS0KCiMjIFRoZSBwb3dlciBvZiB0aGUgYCU+JWAgKHBpcGUpCgpFdmVyeXRoaW5nIHdlIGRpZCBhYm92ZSBjYW4gYmUgY2hhaW5lZCBpbnRvIG9uZSBzZXF1ZW5jZToKCgpgYGB7ciBldmFsPUZBTFNFfQp3aG9fdGlkeSA8LSB3aG9fZGYgJT4lIAogIGdhdGhlcihuZXdfc3BfbTAxNDpuZXdyZWxfZjY1LCBrZXkgPSAia2V5IiwgdmFsdWUgPSAidmFsdWUiKSAlPiUgIAogIG11dGF0ZShrZXkgPSBzdHJfcmVwbGFjZShrZXksIHBhdHRlcm4gPSAibmV3cmVsIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gIm5ld19yZWwiKSkgJT4lIAogIHNlcGFyYXRlKGNvbCA9IGtleSwgaW50byA9IGMoIm5ldyIsICJ0eXBlIiwgInNleGFnZSIpLCBzZXAgPSAiXyIpICU+JSAKICBzZXBhcmF0ZShjb2wgPSBzZXhhZ2UsIGludG8gPSBjKCJzZXgiLCAiYWdlIiksIHNlcCA9IDEpICU+JSAKICBzZWxlY3QoLWlzbzIsIC1pc28zLCAtbmV3KSAlPiUgCiAgbmEub21pdCgpICU+JSAKICByZW5hbWUoImNhc2VzIiA9IHZhbHVlKQpgYGAKCi0tLQoKIyMgQk9OVVMKCiMjIyBBIEdhcG1pbmRlciB0aWR5IGRhdGFzZXQgcmVhZCBpbiBmcm9tIGEgR29vZ2xlIFNoZWV0IQoKLSBJJ3ZlIHVwZGF0ZWQgdGhlIGBnYXBtaW5kZXJgIGRhdGEgc2V0IGF2YWlsYWJsZSBpbiB0aGUgYGdhcG1pbmRlcmAgUiBkYXRhIHBhY2thZ2UgYnkgSmVubnkgQnJ5YW4gW2hlcmVdKGh0dHBzOi8vZ2l0aHViLmNvbS9qZW5ueWJjL2dhcG1pbmRlci8pLiAgSmVubnkgcHJvdmlkZXMgW2luc3RydWN0aW9uc10oaHR0cHM6Ly9naXRodWIuY29tL2plbm55YmMvZ2FwbWluZGVyL3RyZWUvbWFzdGVyL2RhdGEtcmF3KSBmb3IgcmVjcmVhdGluZyB0aGUgZGF0YS4KCi0tLQoKIyMgQk9OVVMKCi0gWW91IGNhbiBkb3dubG9hZCB0aGUgdXBkYXRlZCBkYXRhIGZyb20gR29vZ2xlIFNoZWV0cyBieSBydW5uaW5nIHRoZSBmb2xsb3dpbmcgaW4gUjoKCmBgYHtyIGV2YWw9RkFMU0V9CiMgTGluayBpcyBodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9zcHJlYWRzaGVldHMvZC8xOEw1WmlYZDFDUTk3WFdTcWIwNHgxWVE0bmNzRU9kUjdlSHpnWDBaSXVQQS9lZGl0P3VzcD1zaGFyaW5nCmxpYnJhcnkoZ29vZ2xlc2hlZXRzKQp1cGRhdGVkX2dhcCA8LSBnc19rZXkoIjE4TDVaaVhkMUNROTdYV1NxYjA0eDFZUTRuY3NFT2RSN2VIemdYMFpJdVBBIikgJT4lCiAgZ3NfcmVhZCgpCmBgYAoKCi0gQSBzY3JpcHQgZ29pbmcgdGhyb3VnaCB0aGUgc3RlcHMgdG8gdGFrZSB0aGUgIm1lc3N5IiBvcmlnaW5hbCBHYXBtaW5kZXIub3JnIGZpbGVzIGFuZCB0dXJuIHRoZW0gaW50byB0aGlzIHRpZHkgZGF0YXNldCBpcyBhdmFpbGFibGUgW2hlcmVdKGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9pc21heWMvdGlkeXZlcnNlX3dvcmtzaG9wcy9tYXN0ZXIvaW1wb3J0aW5nX3RpZHlpbmcvZGF0YS9jbGVhbmluZy5SKS4KCi0tLQoKIyMgUHJhY3RpY2UgKGFmdGVyIHRoZSBib290Y2FtcCkKClRyeSB0byB0aWR5IHRoZSBvdGhlciBkYXRhIHNldHMgeW91IGRvd25sb2FkZWQgYW5kIGltcG9ydGVkIG9yIG90aGVyIGRhdGEgc2V0cyB5b3UgaGF2ZSEKCi0tLQoKbmFtZTogbW9kZWwKY2xhc3M6IGludmVyc2UsIGNlbnRlciwgbWlkZGxlCgojIERhdGEgTW9kZWxpbmcKCgotLS0KCgojIyBNb2RlbGluZwoKMS4gRXhwZXJpZW5jZSB3aXRoIGBnZ3Bsb3QyYCBwYWNrYWdlIGFuZCBrbm93bGVkZ2Ugb2YgdGhlIEdyYW1tYXIgb2YgR3JhcGhpY3MgcHJpbWVzIHN0dWRlbnRzIGZvciBtb2RlbGluZwoxLiBVc2Ugb2YgdGhlIGBicm9vbWAgcGFja2FnZSB0byB1bnBhY2sgcmVncmVzc2lvbiBvdXRwdXQgaW50byBhIHRpZHkgZm9ybWF0CgotLS0KCiMjIDEuIGBnZ3Bsb3QyYCBQcmltZXMgUmVncmVzc2lvbgoKRXhhbXBsZToKCiogQWxsIEFsYXNrYW4gQWlybGluZXMgYW5kIEZyb250aWVyIGZsaWdodHMgbGVhdmluZyBOWUMgaW4gMjAxMwoqIFdlIHdhbnQgdG8gc3R1ZHkgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRlbXBlcmF0dXJlIGFuZCBkZXBhcnR1cmUgZGVsYXkKKiBGb3Igc3VtbWVyIChKdW5lLCBKdWx5LCBBdWd1c3QpIGFuZCBub24tc3VtbWVyIG1vbnRocyBzZXBhcmF0ZWx5CgpJbnZvbHZlcyBmb3VyIHZhcmlhYmxlczogCgotIGBjYXJyaWVyYCwgYHRlbXBgLCBgZGVwX2RlbGF5YCwgYHN1bW1lcmAKCi0tLQoKIyMgMS4gYGdncGxvdDJgIFByaW1lcyBSZWdyZXNzaW9uCgpgYGB7cn0KZmxpZ2h0c19zdWJzZXQgPC0gZmxpZ2h0cyAlPiUgCiAgZmlsdGVyKGNhcnJpZXIgPT0gIkFTIiB8IGNhcnJpZXIgPT0gIkY5IikgJT4lIAogIGxlZnRfam9pbih3ZWF0aGVyLCBieT1jKCJ5ZWFyIiwgIm1vbnRoIiwgImRheSIsICJob3VyIiwgIm9yaWdpbiIpKSAlPiUgCiAgZmlsdGVyKGRlcF9kZWxheSA8IDI1MCkgJT4lIAogIG11dGF0ZShzdW1tZXIgPSBpZmVsc2UobW9udGggPT0gNiB8IG1vbnRoID09IDcgfCBtb250aCA9PSA4LCAiU3VtbWVyIEZsaWdodHMiLCAiTm9uLVN1bW1lciBGbGlnaHRzIikpCmBgYAoKLS0tCgpgYGB7ciwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTAuNX0KZ2dwbG90KGRhdGEgPSBmbGlnaHRzX3N1YnNldCwgCiAgICBtYXBwaW5nID0gYWVzKHggPSB0ZW1wLCB5ID0gZGVwX2RlbGF5LCBjb2xvciA9IGNhcnJpZXIpKSArIAogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSkgKwogIGZhY2V0X3dyYXAofiBzdW1tZXIpCmBgYAoKLS0tCgojIyAxLiBgZ2dwbG90MmAgUHJpbWVzIFJlZ3Jlc3Npb24KCldoeT8gRGlnIGRlZXBlciBpbnRvIGRhdGEuIExvb2sgYXQgYG9yaWdpbmAgYW5kIGBkZXN0YCB2YXJpYWJsZXMgYXMgd2VsbDoKCjxicj4gCgpgYGB7cn0KZmxpZ2h0c19zdWJzZXQgJT4lIAogIGdyb3VwX2J5KGNhcnJpZXIsIG9yaWdpbiwgZGVzdCkgJT4lIAogIHN1bW1hcmlzZShgTnVtYmVyIG9mIEZsaWdodHNgID0gbigpKQpgYGAKCi0tLQoKCiMjIDIuIGBicm9vbWAgUGFja2FnZQoKKiBUaGUgYGJyb29tYCBwYWNrYWdlIHRha2VzIHRoZSBtZXNzeSBvdXRwdXQgb2YgYnVpbHQtaW4gbW9kZWxpbmcgZnVuY3Rpb25zIGluIFIsIHN1Y2ggYXMKYGxtYCwgYG5sc2AsIG9yIGB0LnRlc3RgLCBhbmQgdHVybnMgdGhlbSBpbnRvIHRpZHkgZGF0YSBmcmFtZXMuCiogRml0cyBpbiB3aXRoIGB0aWR5dmVyc2VgIGVjb3N5c3RlbQoqIFRoaXMgd29ya3MgZm9yIFttYW55IFIgZGF0YSB0eXBlc10oaHR0cHM6Ly9naXRodWIuY29tL3RpZHl2ZXJzZS9icm9vbSNhdmFpbGFibGUtdGlkaWVycykhCgotLS0KCiMjIDIuIGBicm9vbWAgUGFja2FnZQoKSW4gb3VyIGNhc2UsIGBicm9vbWAgZnVuY3Rpb25zIHRha2UgYGxtYCBvYmplY3RzIGFzIGlucHV0cyBhbmQgcmV0dXJuIHRoZSBmb2xsb3dpbmcgaW4gdGlkeSBmb3JtYXQhCgoqIGB0aWR5KClgOiByZWdyZXNzaW9uIG91dHB1dCB0YWJsZQoqIGBhdWdtZW50KClgOiBwb2ludC1ieS1wb2ludCB2YWx1ZXMgKGZpdHRlZCB2YWx1ZXMsIHJlc2lkdWFscywgcHJlZGljdGVkIHZhbHVlcykKKiBgZ2xhbmNlKClgOiBzY2FsYXIgc3VtbWFyaWVzIGxpa2UgPGxhcmdlPiAkUl4yJCA8L2xhcmdlPiwgCgotLS0KCiMjIDIuIGBicm9vbWAgUGFja2FnZQoKRXhhbXBsZQoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KG55Y2ZsaWdodHMxMykKbGlicmFyeShrbml0cikKbGlicmFyeShicm9vbSkKc2V0LnNlZWQoMjAxNykKCiMgTG9hZCBBbGFza2EgZGF0YSwgZGVsZXRpbmcgcm93cyB0aGF0IGhhdmUgbWlzc2luZyBkZXBhcnR1cmUgZGVsYXkKIyBvciBhcnJpdmFsIGRlbGF5IGRhdGEKYWxhc2thX2ZsaWdodHMgPC0gZmxpZ2h0cyAlPiUgCiAgZmlsdGVyKGNhcnJpZXIgPT0gIkFTIikgJT4lIAogIGZpbHRlcighaXMubmEoZGVwX2RlbGF5KSAmICFpcy5uYShhcnJfZGVsYXkpKSAlPiUgCiAgc2FtcGxlX24oNTApCmBgYAoKLS0tCgpgYGB7cn0KIyBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyBQbG90IG9mIHNhbXBsZSBvZiBwb2ludHM6CmdncGxvdChkYXRhID0gYWxhc2thX2ZsaWdodHMsIG1hcHBpbmcgPSBhZXMoeCA9IGRlcF9kZWxheSwgeSA9IGFycl9kZWxheSkpICsgCiAgIGdlb21fcG9pbnQoKQpgYGAKCi0tLQoKYGBge3J9CiMgQ29ycmVsYXRpb24gY29lZmZpY2llbnQ6CmFsYXNrYV9mbGlnaHRzICU+JSBzdW1tYXJpemUoY29ycmVsID0gY29yKGRlcF9kZWxheSwgYXJyX2RlbGF5KSkKCiMgQWRkIHJlZ3Jlc3Npb24gbGluZQpnZ3Bsb3QoZGF0YSA9IGFsYXNrYV9mbGlnaHRzLCBtYXBwaW5nID0gYWVzKHggPSBkZXBfZGVsYXksIHkgPSBhcnJfZGVsYXkpKSArIAogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAicmVkIikKYGBgCgotLS0KCmBgYHtyfQojIEZpdCBSZWdyZXNzaW9uIGFuZCBTdHVkeSBPdXRwdXQgd2l0aCBicm9vbSBQYWNrYWdlLS0tLS0tLS0tLS0tLS0tLS0tLQojIEZpdCByZWdyZXNzaW9uCm9wdGlvbnMoc2NpcGVuID0gNikgIyBTZXQgc2NpZW50aWZpYyBub3RhdGlvbgpkZWxheV9maXQgPC0gbG0oZm9ybXVsYSA9IGFycl9kZWxheSB+IGRlcF9kZWxheSwgZGF0YSA9IGFsYXNrYV9mbGlnaHRzKQoKIyAxLiBicm9vbTo6dGlkeSgpIHJlZ3Jlc3Npb24gdGFibGUgd2l0aCBjb25maWRlbmNlIGludGVydmFscyAKIyBhbmQgbm8gcC12YWx1ZSBzdGFycwpyZWdyZXNzaW9uX3RhYmxlIDwtIGRlbGF5X2ZpdCAlPiUgCiAgdGlkeShjb25mLmludCA9IFRSVUUpCnJlZ3Jlc3Npb25fdGFibGUKYGBgCgotLS0KCmBgYHtyfQojIDIuIGJyb29tOjphdWdtZW50KCkgZm9yIHBvaW50LWJ5LXBvaW50IHZhbHVlcwpyZWdyZXNzaW9uX3BvaW50cyA8LSBkZWxheV9maXQgJT4lIAogIGF1Z21lbnQoKSAlPiUgCiAgc2VsZWN0KGFycl9kZWxheSwgZGVwX2RlbGF5LCAuZml0dGVkLCAucmVzaWQpIApyZWdyZXNzaW9uX3BvaW50cwpgYGAKCi0tLQoKYGBge3J9CiMgYW5kIGZvciBwcmVkaWN0aW9uCm5ld19mbGlnaHRzIDwtIGRhdGFfZnJhbWUoZGVwX2RlbGF5ID0gYygyNSwgMzAsIDE1KSkKZGVsYXlfZml0ICU+JSAKICBhdWdtZW50KG5ld2RhdGEgPSBuZXdfZmxpZ2h0cykKYGBgCgotLS0KCmBgYHtyfQojIDMuIGJyb29tOjpnbGFuY2UoKSBzY2FsYXIgc3VtbWFyaWVzIG9mIHJlZ3Jlc3Npb24KcmVncmVzc2lvbl9zdW1tYXJpZXMgPC0gZGVsYXlfZml0ICU+JSAKICBnbGFuY2UoKSAKcmVncmVzc2lvbl9zdW1tYXJpZXMKYGBgCgotLS0KCmBgYHtyfQojIFJlc2lkdWFsIEFuYWx5c2lzLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCmdncGxvdChkYXRhID0gcmVncmVzc2lvbl9wb2ludHMsIG1hcHBpbmcgPSBhZXMoeCA9IC5yZXNpZCkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aD0xMCwgY29sb3IgPSAid2hpdGUiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgY29sb3IgPSAiYmx1ZSIpCmBgYAoKLS0tCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSByZWdyZXNzaW9uX3BvaW50cywgbWFwcGluZyA9IGFlcyh4ID0gLmZpdHRlZCwgeSA9IC5yZXNpZCkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDAsIHNsb3BlID0gMCwgY29sb3IgPSAiYmx1ZSIpCmBgYAoKLS0tCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSByZWdyZXNzaW9uX3BvaW50cywgbWFwcGluZyA9IGFlcyhzYW1wbGUgPSAucmVzaWQpKSArCiAgc3RhdF9xcSgpCmBgYAoKLS0tCgpjbGFzczogY2VudGVyLCBtaWRkbGUsIGludmVyc2UKbmFtZTogcm1hcmtkb3duCgojIERhdGEgQ29tbXVuaWNhdGluZwoKCi0tLQoKIyMgV2hhdCBpcyBNYXJrZG93bj8KCiAtIEEgInBsYWludGV4dCBmb3JtYXR0aW5nIHN5bnRheCIKIC0gVHlwZSBpbiBwbGFpbiB0ZXh0LCByZW5kZXIgdG8gbW9yZSBjb21wbGV4IGZvcm1hdHMKIC0gT25lIHN0ZXAgYmV5b25kIHdyaXRpbmcgYSBgdHh0YCBmaWxlCiAtIFJlbmRlciB0byBIVE1MLCBQREYsIERPQ1gsIGV0Yy4gdXNpbmcgUGFuZG9jCgotLS0KCiMjIFdoYXQgZG9lcyBpdCBsb29rIGxpa2U/CgoubGVmdC1jb2x1bW5bCmBgYAogICMgSGVhZGVyIDEKICAKICAjIyBIZWFkZXIgMgogIAogIE5vcm1hbCBwYXJhZ3JhcGhzIG9mIHRleHQgZ28gaGVyZS4KICAKICAqKkknbSBib2xkKioKICAKICBbbGlua3MhXShodHRwOi8vcnN0dWRpby5jb20pCiAgCiAgICogVW5vcmRlcmVkCiAgICogTGlzdHMgICAKICAgCiAgQW5kICBUYWJsZXMKICAtLS0tIC0tLS0tLS0KICBMaWtlIFRoaXMKICAKYGBgCl0KCi5yaWdodC1jb2x1bW5bCjxpbWcgc3JjPSJmaWd1cmUvbWFya2Rvd24ucG5nIiBhbHQ9Im1hcmtkb3duIiBzdHlsZT0id2lkdGg6IDI3MHB4OyIvPgpdCgotLS0KCiMjIFdoYXQgaXMgUiBNYXJrZG93bj8KICAKLSAiTGl0ZXJhdGUgcHJvZ3JhbW1pbmciCi0gRW1iZWQgUiBjb2RlIGluIGEgTWFya2Rvd24gZG9jdW1lbnQKLSBSZW5kZXJzIHRleHR1YWwgb3V0cHV0IGFsb25nIHdpdGggZ3JhcGhpY3MKCioqKgoKLmxlZnQtY29sdW1uWwpgYGAKCmALYAtge3IgY2h1bmsxfQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkobnljZmxpZ2h0czEzKQpwZHhfZmxpZ2h0cyA8LSBmbGlnaHRzICU+JSAKICBmaWx0ZXIoZGVzdCA9PSAiUERYIiwgbW9udGggPT0gNSkKbnJvdyhwZHhfZmxpZ2h0cykKYAtgC2AKCmALYAtge3IgY2h1bmsyfQpnZ3Bsb3QoZGF0YSA9IHBkeF9mbGlnaHRzLAogIG1hcHBpbmcgPSBhZXMoeCA9IGFycl9kZWxheSwgCiAgICAgICAgICAgICAgICB5ID0gZGVwX2RlbGF5KSkgKwogIGdlb21fcG9pbnQoKQpgC2ALYAoKYGBgCl0KCi5yaWdodC1jb2x1bW5bCmBgYHtyLCBmaWcud2lkdGg9NC41LCBmaWcuaGVpZ2h0PTQsIGVjaG89RkFMU0V9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShueWNmbGlnaHRzMTMpCnBkeF9mbGlnaHRzIDwtIGZsaWdodHMgJT4lIAogIGZpbHRlcihkZXN0ID09ICJQRFgiLCBtb250aCA9PSA1KQpucm93KHBkeF9mbGlnaHRzKQpnZ3Bsb3QoZGF0YSA9IHBkeF9mbGlnaHRzLAogIG1hcHBpbmcgPSBhZXMoeCA9IGFycl9kZWxheSwgCiAgICAgICAgICAgICAgICB5ID0gZGVwX2RlbGF5KSkgKwogIGdlb21fcG9pbnQoKQpgYGAKXQoKLS0tCgojIyBQcmFjdGljZQoKVHVybiBhIHN0YXRpc3RpY2FsIGFuYWx5c2lzIHlvdSBoYXZlIGNvbmR1Y3RlZCBpbnRvIGFuIFIgTWFya2Rvd24gZG9jdW1lbnQuCgotIFlvdSBjYW4gYWxzbyBwdWJsaXNoIG9ubGluZSBlYXNpbHkgdG8gPGh0dHA6Ly9ycHVicy5jb20+CgotLS0KCmNsYXNzOiBtaWRkbGUKCiMgVGhhbmtzIGZvciBhdHRlbmRpbmchCgotIFNsaWRlcyBjcmVhdGVkIHZpYSB0aGUgUiBwYWNrYWdlIFt4YXJpbmdhbl0oaHR0cHM6Ly9naXRodWIuY29tL3lpaHVpL3hhcmluZ2FuKSBieSBZaWh1aSBYaWUKLSBTb3VyY2UgY29kZSBmb3IgdGhlc2Ugc2xpZGVzIGFuZCB0aGUgd2VicGFnZSBhdCA8aHR0cHM6Ly9naXRodWIuY29tL2lzbWF5Yy9wb1J0bGFuZC1ib290Y2FtcDE3Pg==